Template argument deduction for parenthesized initialization of aggregates in C++

Viewed 200

In the following code there is an initialization of A<T> objects with template argument deduction using two forms distinct by the type of braces:

template<typename T>
struct A{ T x; };

int main() {
    static_assert( A{1}.x == 1 ); //#1: ok in GCC and MSVC
    static_assert( A(1).x == 1 ); //#2: ok in GCC only
}

The first way is accepted by both GCC and MSVC, while the second one is ok for GCC only while MSVC prints errors:

error C2641: cannot deduce template arguments for 'A'
error C2780: 'A<T> A(void)': expects 0 arguments - 1 provided
error C2784: 'A<T> A(A<T>)': could not deduce template argument for 'A<T>' from 'int'

Demo: https://gcc.godbolt.org/z/97G1acqPr

Is it a bug in MSVC?

2 Answers

This is a bug in MSVC.

The following papers were all introduced in C++20:

Whilst MSVC lists them all as implemented in their Microsoft C/C++ language conformance by Visual Studio version pages, it seems whilst they have correctly implemented them in isolation

// OK (P0960R3, P1975R0)
struct A { int x; };
A a(1);

// OK (P2131R0)
template<typename T>
struct B { T x; };
B b{1};

// rejects-invalid (allowed by the union of the papers)
template<typename T>
struct C { T x; };
C c(1);

MSVC seems to have missed implementing the union of the papers. I have not, however, been able to find an open bug report.

These lines being well-formed relies on an aggregate deduction candidate, which provides a way for T to be deduced from aggregate intialization lists. This feature is indifferent to the syntax, so failing on either one but not the other is already inconsistent.

In MSVC's case, it's the combination of class template parameter deduction and parenthesized aggregate intialization that is causing the issue (the latter works fine in isolation). MSVC also fails to compile A a(1);, which is more obviously well-formed.

Related