Мне трудно понять, как работает std::initializer_list
. Я проверила другие вопросы, но ничего подходящего не нашла (а может не увидела?).
Скажем, у меня есть это:
template<typename T>
struct Point
{
T x,y;
};
template<typename T>
struct A
{
std::vector<Point<T>> v;
};
Затем я могу построить с помощью:
int main()
{
A<int> a{ std::vector<Point<int>> { {4,4}, {5,5},{6,6} } };
}
Но я хотел бы сделать все проще, поэтому я могу написать:
int main()
{
A<int> a( { {4,4}, {5,5},{6,6} } );
}
Я пытался:
template<typename T>
struct A
{
std::vector<Point<T>> v;
template<typename U>
A( const std::initializer_list<Point<U>>& il ) : v{il}
{}
};
Но это не получается, смотрите демо вживую.
Как я могу написать конструктор, позволяющий это? Это вообще возможно?
Ваши конструкторы не должны быть шаблонными, ваш класс уже есть. {..}
не имеет типа и может быть сведен к очень небольшому количеству типов.
После удаления работает следующее:
template<typename T>
struct A
{
std::vector<Point<T>> v;
A( const std::vector<Point<T>>& in ) : v(in) {}
A( const std::initializer_list<Point<T>>& il ): v{il}
{}
};
int main()
{
std::vector<Point<int>> v{ {4,4}, {5,5},{6,6} };
A<int> a1( std::vector<Point<int>> { {4,4}, {5,5},{6,6} } ); // this is fine
assert( a1.v.size() == 3 );
A<int> a2{{4,4}, {5,5}, {6,6} };
assert( a2.v.size() == 3 );
A<int> a3({{4,4}, {5,5}, {6,6} });
}
В C++20 есть функция, называемая инициализацией агрегатов в скобках, которая позволяет правильно формировать заданный синтаксис.
template<typename T>
struct Point
{
T x, y;
};
template<typename T>
struct A
{
std::vector<Point<T>> v;
};
int main()
{
//--------------v------------------------v---> parenthesis ok with c++20, replace () with {} for pre-c++20
A<int> a( { {4, 4}, {5, 5}, {6, 6} } );
}
Это означает, что если вы работаете с версиями до C++20, вы можете заменить круглые скобки ()
фигурными скобками {}
. демо С++ 14
Благодарить! Но, похоже, для этого требуется С++ 20, а не С++ 17: ваша ссылка не работает при переключении на -std=c++17
. Я бы предпочел придерживаться С++ 14.
Во-первых, ваш желаемый синтаксис почти работает (без добавления конструктора к A
), просто замените (...)
на {...}
.
int main()
{
A<int> a{{ {4,4}, {5,5},{6,6} }};
}
Во-вторых, если вы все еще хотите написать конструктор для A
, не используйте для него std::initializer_list
! std::vector
уже делает это, так что вам не нужно. Просто передайте вектор:
template<typename T>
struct A
{
std::vector<Point<T>> v;
A(std::vector<Point<T>> v) : v(std::move(v)) {}
};
int main()
{
A<int> a( { {4,4}, {5,5},{6,6} } );
}
Да, я действительно пропустил синтаксис двойных фигурных скобок, спасибо!
Спасибо! Действительно работает. Дело в том, что я создал шаблон конструктора для обработки возможности инициализации с другим типом FP (за счет потенциальной потери точности). Произнесите что-нибудь вроде
A<float> a{{4.4,5.5}};
и приступайте к копированию поэлементно в теле конструктора. Но меня устраивает решение с таким же типом!