Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 537
Fedor Avatar asked Nov 14 '21 08:11

Fedor


People also ask

Why does CTAD argument deduction fail in C++17?

If you compile this in C++17, you’ll likely get some error about “CTAD argument deduction failed” or “cannot deduce template arguments” or “No viable constructor or deduction guide”. This is because in C++17, CTAD doesn’t know how to deduce the template arguments for aggregate class templates.

What is template argument deduction in C++?

Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.

Can a template parameter be deduced from a default argument?

Type template parameter cannot be deduced from the type of a function default argument: Deduction of template template parameter can use the type used in the template specialization used in the function call: Besides function calls and operator expressions, template argument deduction is used in the following situations:

How to avoid explicitly specifying arguments in a class template?

Before class template argument deduction was introduced, a common approach to avoiding explicitly specifying arguments is to use a function template: The following behavior-changing defect reports were applied retroactively to previously published C++ standards.


Video Answer


2 Answers

This is a bug in MSVC.

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

  • P0960R3: Allow initializing aggregates from a parenthesized list of values
  • P1975R0: Fixing the wording of parenthesized aggregate-initialization
  • P2131R0: Fixing CTAD for aggregates

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.

like image 64
dfrib Avatar answered Oct 16 '22 08:10

dfrib


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.

like image 3
Columbo Avatar answered Oct 16 '22 09:10

Columbo