c++ - CTAD、initializer_list、非显式构造函数和函数调用

标签 c++ templates c++17

基本上,我想要的是 multi_types std::initializer_list

template<typename ...As>
struct Foo {
Foo(As...){}
};

template<typename ...As>
void f(Foo<As...>) {}

int main() {
  f(Foo{5, 3.f}); // 1) compile
  f({}); // 2) compile
  f({5, 3}); // 3) error
  f({5, 3.8}); // 4) error
  return 0;
}

我确实理解第一个示例编译的原因。但是,我不明白为什么第二个编译但其他的不编译。对我来说,如果第三个和第四个不编译,第二个也不应该编译。有没有办法使第三次和第四次编译?

最佳答案

However, I do not understand why the second compiles but the others don't [compile].

示例 3 和 4 无法编译,因为推导的模板参数与您期望的不同。

当您编写对函数模板的调用 ( f({5, 3})) 时 template<typename ...As> void f(Foo<As...>) ,编译器需要推断出任何缺失的模板参数(...As)。这些缺失的模板参数首先通过比较函数参数 ({5, 3}) 和函数参数 (Foo<As...>) 推导出来。如果函数参数是初始化列表 ( {5, 3} ) [1],跳过函数参数的模板参数推导 ( Foo<As...> ):

N4659 [temp.deduct.call] 17.8.2.1(1):

[...] an initializer list argument causes the parameter to be considered a non-deduced context (17.8.2.5).

N4659 [temp.deduct.type] 17.8.2.5(5.6):

[Non-deduced contexts include a] function parameter for which the associated argument is an initializer list (11.6.4) [...]

因为尾随的模板参数包 ( As... ) 没有被任何函数参数推导出来,它被推导出为空:

N4659 [temp.arg.explicit] 17.8.1(3):

A trailing template parameter pack (17.5.3) not otherwise deduced will be deduced to an empty sequence of template arguments.

对于 f({5, 3}) ,编译器推断模板参数是 <> (空),因此被调用的特化是void f(Foo<>) 。重要提示:无论初始化列表中有什么,都会选择此特化。这解释了编译器给出的诊断:

Clang:
error: no matching function for call to 'f'
note: candidate function [with As = <>] not viable: cannot convert initializer list argument to 'Foo<>'

GCC:
error: could not convert '{5, 3}' from '' to 'Foo<>'

MSVC:
error C2664: 'void f<>(Foo<>)': cannot convert argument 1 from 'initializer list' to 'Foo<>'
note: No constructor could take the source type, or constructor overload resolution was ambiguous

在函数调用中,函数参数使用函数参数中的复制初始化 进行初始化。以下语句使用与您的示例初始化 f 的参数相同的规则初始化变量:

Foo<> x = {};        // Example 2
Foo<> x = {5, 3};    // Example 3
Foo<> x = {5, 3.8};  // Example 4

[1] 简而言之,如果函数参数既不是 std::initializer_list<T>也不T[n]

关于c++ - CTAD、initializer_list、非显式构造函数和函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54824308/

相关文章:

WPF/XAML : multiple controls using the same events - is there an easier way?

c++ - 编译过度对齐的动态分配变量时出现 icpc 错误

c++ - 如何重置 boost::sml::sm 实例

c++ - 对象成员和标准类型的模板函数

c++ - static_assert 无法将 const char* 模板参数识别为 constexpr : g++ bug?

c++ - 不按特定顺序跳过多个循环(C++)

c++ - 满足条件时如何在中间停止折叠表达式函数调用并返回该值?

c++ - 使用 union 体通过 SPI 将 float 从一个 arduino 发送到另一个 arduino

c++ - 以正确的方式从您的位置找到最近的对象 QT c++

c++ - 我知道函数调用中存在歧义。有没有办法调用 foo() 函数?