Почему стандартная предпочтительная инициализация круглых скобок для `make_‹something›`?

Стандартные функции std::make_, такие как:

  • std::make_unique и std::make_shared
  • std::make_tuple
  • std::make_from_tuple

все используют внутреннюю инициализацию с круглыми скобками, а не фигурные скобки.

Например, make_from_tuple в соответствии со стандартом предпочитает возвращать T(params...), а не чем T{params...}.

В результате следующие действия являются незаконными:

auto vec = std::make_from_tuple<std::vector<int>>(std::make_tuple());
auto arr = std::make_from_tuple<std::array<int, 2>>(std::make_tuple(9, 8));

^создание std::array из tuple, как указано выше, недопустимо также с C++20, как p0960 - позволяя инициализировать агрегаты из списка значений в скобках, становящегося частью спецификация C++20 не допускает такой инициализации для std::array, так как его внутренний тип — T[size], который не может быть инициализирован из списка значений (круглые скобки уже удаляются инициализацией std::array).


В тех случаях, когда это работает, выбор инициализации скобок вместо фигурных скобок имеет смысл:

auto vec2 = std::make_from_tuple<std::vector<int>>(std::make_tuple(2, 3));
// a vector with the values: {3, 3} surprise? :-)

(Конечно, выше приведены забавные примеры. Предоставленный кортеж может быть предоставлен извне).

С curly_make_from_tuple вроде:

template<typename T, typename tuple_t>
constexpr auto curly_make_from_tuple(tuple_t&& tuple) {
    constexpr auto get_T = [](auto&& ... x){ return T{std::forward<decltype(x)>(x) ... }; };
    return std::apply(get_T, std::forward<tuple_t>(tuple));
}

все приведенные выше случаи будут работать, и можно утверждать, что это более естественно:

auto arr = curly_make_from_tuple<std::array<int, 2>>(std::make_tuple(9, 8)); // {9, 8}
auto vec = curly_make_from_tuple<std::vector<int>>(std::make_tuple());       // {}
auto vec2 = curly_make_from_tuple<std::vector<int>>(std::make_tuple(2, 3));  // {2, 3}

Возникает вопрос: почему стандарт выбрал инициализацию с круглыми скобками вместо фигурных скобок?


Ссылки по теме:

Аналогичный вопрос с точки зрения эффективности: Почему реализация make_tuple не возвращается через инициализацию фигурной скобки?

Хорошее обсуждение и предложения по добавлению инициализации фигурных скобок опция для утилит `make_`.

Исходный документ с предложением make_from_tuple, P0209r2, кажется, не обсуждают две альтернативы T(params...) и T{params...}, может быть, потому, что все аналогичные make_ служебные методы уже использовали инициализацию в круглых скобках.


person Amir Kirsh    schedule 26.05.2020    source источник
comment
Вызов функции всегда использует круглые скобки. Это синтаксис языка. Фигурные скобки предназначены для списков инициализаторов.   -  person sanitizedUser    schedule 26.05.2020
comment
Вы спрашиваете, почему они используют T(std::forward<decltype(x)>(x) ... ) вместо T{std::forward<decltype(x)>(x) ... }?   -  person NathanOliver    schedule 26.05.2020
comment
@NathanOliver да, игнорируя причудливые варианты поддержки обоих (как обсуждается во второй ссылке в конце), если один из них должен поддерживаться, почему круглые скобки?   -  person Amir Kirsh    schedule 26.05.2020
comment
Это не инициализация, это вызов функции std::make_unique, std::make_shared, std::make_tuple и т. д. не инициализируют вещи, они возвращают объекты, и их преимуществами являются потокобезопасность, простота и т. д.   -  person asmmo    schedule 26.05.2020
comment
@asmmo вопрос в внутренней реализации этих функций.   -  person Amir Kirsh    schedule 26.05.2020
comment
Другой связанный вопрос с несколькими интересными ответами можно найти здесь: > stackoverflow.com/questions/55141594/   -  person Yehezkel B.    schedule 26.05.2020


Ответы (1)


Потому что было невозможно инициализировать структуру с помощью braced-init-list в C++98.

Таким образом, для согласованности новые стандартные библиотечные функции используют ту же форму инициализации, что и в STL.

Более того, он никогда не менялся на list-initialization по соображениям совместимости: list-initialization не обязательно имеет то же значение, что и эквивалентная форма инициализации в скобках.

person Oliv    schedule 26.05.2020
comment
Какая библиотечная функция до C++11 создавала такой объект? Вероятно, нет, так как он основан на вариативном шаблоне. Так что, если бы все такие функции только что появились в C++11 или позже, он мог бы использовать инициализацию фигурными скобками. Конечно, должен быть выбран один, если не использовать причудливый подход для поддержки обоих, но рассматривал ли комитет оба? Было ли это преднамеренным решением? - person Amir Kirsh; 27.05.2020
comment
@AmirKirsh Например, распределитель STL для создания копии. - person Oliv; 27.05.2020