C++ 中聚合的带括号初始化的模板参数推导

Posted

技术标签:

【中文标题】C++ 中聚合的带括号初始化的模板参数推导【英文标题】:Template argument deduction for parenthesized initialization of aggregates in C++ 【发布时间】:2021-12-25 21:32:00 【问题描述】:

在下面的代码中,有一个 A<T> 对象的初始化,模板参数推导使用两种不同的大括号类型:

template<typename T>
struct A T x; ;

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

GCC 和 MSVC 都接受第一种方式,而第二种方式仅在 MSVC 打印错误时适用于 GCC:

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'

演示:https://gcc.godbolt.org/z/97G1acqPr

这是 MSVC 中的错误吗?

【问题讨论】:

不是 100% 肯定,但似乎 MSVC 在这里错了。如果您添加构造函数,两者都可以工作:constexpr A(T v= T) : x(v) 【参考方案1】:

这是 MSVC 中的一个错误。

以下论文均在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

虽然 MSVC 将它们全部列出为在其 Microsoft C/C++ language conformance by Visual Studio version 页面中实现,但似乎它们已单独正确实现它们

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

// OK (P2131R0)
template<typename T>
struct B  T x; ;
B b1;

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

MSVC 似乎错过了实施论文联合。但是,我还没有找到打开的错误报告。

【讨论】:

谢谢,我提交了 MSVC 错误:developercommunity.visualstudio.com/t/…【参考方案2】:

这些格式良好的行依赖于aggregate deduction candidate,它为T 提供了一种从聚合初始化列表中推导出来的方法。此功能与语法无关,因此其中一个失败而另一个失败已经是不一致的。

在 MSVC 的情况下,是类模板参数推导和带括号的聚合初始化的组合导致了问题(后者单独工作正常)。 MSVC 还有fails to compile A a(1);,更明显是格式良好的。

【讨论】:

以上是关于C++ 中聚合的带括号初始化的模板参数推导的主要内容,如果未能解决你的问题,请参考以下文章

C++进阶第二十五篇——C++11(列表初始化+变量类型推导+右值引用和移动语义+新的类功能+可变模板参数)

C++进阶第二十五篇——C++11(列表初始化+变量类型推导+右值引用和移动语义+新的类功能+可变模板参数)

C++进阶第二十五篇——C++11(列表初始化+变量类型推导+右值引用和移动语义+新的类功能+可变模板参数)

如何编写聚合模板别名的推导指南?

接收 std::pair 作为参数并从花括号列表初始化推导出类型的模板化函数

C++学习:Effective Modern C++条款