c++ - 带数组的聚合模板的模板参数推导

标签 c++ templates language-lawyer c++20

考虑以下程序:

template<typename T>
struct A { T t[2]; };

int main()
{
   A a{1}; // only one value provided for 2-element array
   return a.t[0];
}

在 C++20 模式下,它在 gcc 中编译得很好,但在 Visual Studio 中失败并显示错误:
<source>(6): error C2641: cannot deduce template arguments for 'A'
<source>(6): error C2780: 'A<T> A(void)': expects 0 arguments - 1 provided
<source>(2): note: see declaration of 'A'
<source>(6): error C2784: 'A<T> A(A<T>)': could not deduce template argument for 'A<T>' from 'int'
<source>(2): note: see declaration of 'A'
<source>(6): error C2784: 'A<T> A(A<T>)': could not deduce template argument for 'A<T>' from 'int'
<source>(2): note: see declaration of 'A'
<source>(6): error C2780: 'A<T> A(T,T)': expects 2 arguments - 1 provided
<source>(2): note: see declaration of 'A'
https://gcc.godbolt.org/z/6ejfW8G77
这两个编译器中的哪一个是正确的?
( Clang 在这里是没有问题的,因为它还不支持聚合的括号初始化)。
更新:微软承认了这个错误并 promise 很快修复:
https://developercommunity.visualstudio.com/t/template-argument-deduction-fails-in-case-of-aggre/1467260

最佳答案

GCC是对的,代码应该可以接受,类型是a应该推导出为 A<int>使用类模板参数推导 (CTAD) 进行聚合。
N4868(最接近已发布的 C++20 标准)[over.match.class.deduct]/1说(我已经排除了一些在这里不相关的部分):

When resolving a placeholder for a deduced class type where the template-name names a primary class template C, a set of functions and function templates, called the guides of C, is formed comprising:
[...]
In addition, if C is defined and its definition satisfies the conditions for an aggregate class with the assumption that any dependent base class has no virtual functions and no virtual base classes, and the initializer is a non-empty braced-init-list or parenthesized expression-list, and there are no deduction-guides for C, the set contains an additional function template, called the aggregate deduction candidate, defined as follows. Let x1,...,xn be the elements of the initializer-list or designated-initializer-list of the braced-init-list, or of the expression-list. For each xi, let ei be the corresponding aggregate element of C or of one of its (possibly recursive) subaggregates that would be initialized by xi if

  • brace elision is not considered for any aggregate element that has a dependent non-array type or an array type with a value-dependent bound,
    [...]

If there is no such aggregate element ei for any xi, the aggregate deduction candidate is not added to the set. The aggregate deduction candidate is derived as above from a hypothetical constructor C(T1,...,Tn), where

  • [...]
  • otherwise, Ti is the declared type of ei,

[...]

A 的实例化是聚合体。只有 x1,1 .关于不考虑大括号省略的要点不适用,因为我们有一个子聚合( T t[2] ),它是一个具有依赖类型但没有值依赖边界的数组。所以大括号省略被考虑,和1将初始化 t[0] ,即 e1,类型为 T .
所以,合计扣除候选是
template<typename T> A<T> F(T)
可用于推导 A<int> .
MSVC 无法生成此模板。错误消息显示它错误地生成了一个带有两个函数参数的函数。
用于聚合的 CTAD 在 P1816 中指定,但允许此工作的规则出现在另一篇论文中,
P2082 ,解决了几个问题。 MSVC claims to implement both since VS 2019 16.7 ,但仍拒绝自 16.10.3 起的代码。
作为附加数据点,严格 C++20 模式下的 EDG 6.2 接受代码。

关于c++ - 带数组的聚合模板的模板参数推导,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68239834/

相关文章:

c++ - Qt如何在QTableView中选择鼠标下的单词

c++ - 使用 boost::mpl::bool_ 而不是 const bool 的优点

c++ - 未知类型的模板模板参数

c++ - 如何将可变参数从一个模板传递到另一个模板

c++ - 在 C++17 中 i++ + i++ 会评估什么?

c++ - 16 到 32 位整数转换与性能

c++ - 复制抽象基类的对象

c++ - regex_match 和 regex_search 之间的区别?

c++ - 根据标准,这种没有破坏的交换实现是否有效?

c - 这是否避免了 UB