Search code examples
c++tuplesc++17default-constructor

std::make_from_tuple doesn't compile without constructor


I have a simple struct:

struct A
{
    int a;
    int b;
    int c;
    
    // A(int a, int b, int c) : a{a}, b{b}, c{c} { }
};

The constructor is commented for now. I am trying to create object of type A in a such way:

auto t = std::make_tuple(1, 2, 3);
A a = std::make_from_tuple<A>(std::move(t));

but it doesn't compile. MSVC gives a message: <function-style-cast>: cannot convert from initializer_list to _Ty. After I uncomment the constructor of struct A, it starts working.

The question is: why std::make_from_tuple() requires a user-defined constructor instead of default one?


Solution

  • If you look closely at the implementation of make_from_tuple in the standard:

    namespace std {
      template<class T, class Tuple, size_t... I>
        requires is_constructible_v<T, decltype(get<I>(declval<Tuple>()))...>
      constexpr T make-from-tuple-impl(Tuple&& t, index_sequence<I...>) {   
        return T(get<I>(std::forward<Tuple>(t))...);
      }
    }
    

    It uses parentheses (()) to initialize T with direct initialization. Since A is an aggregate, it cannot use parentheses for initialization in C++17, and can only use curly braces ({}) for list initialization.

    It is worth noting that P0960 makes it possible to use parentheses to initialize aggregates in C++20, so your code is well-formed in C++20.