Why do auto and template type deduction differ for braced initializers?
我知道,给定一个初始化初始化程序,
1 2 3 4 5 | auto var = { 1, 2, 3 }; // type deduced as std::initializer_list<int> template<class T> void f(T parameter); f({ 1, 2, 3 }); // doesn't compile; type deduction fails |
我什至知道在C ++ 11标准中指定的位置:14.8.2.5/5 bullet 5:
[It's a non-deduced context if the program has] A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter
does not have std::initializer_list or reference to possibly cv-qualified std::initializer_list
type. [ Example:template void g(T);
g({1,2,3}); // error: no argument deduced for T
—end example ]
我不知道或不了解的是为什么存在类型推断行为上的这种差异。 C ++ 14 CD中的规范与C ++ 11中的规范相同,因此,大概标准化委员会不会将C ++ 11行为视为缺陷。
有人知道为什么
模板不做任何推论有两个重要原因(我记得在与负责人的讨论中提到的两个)
-
有关将来的语言扩展的担忧(您可能会发明多种含义-如果我们想为括号式init列表函数自变量引入完美的转发,该怎么办?)
-
花括号有时可以有效地初始化依赖于函数的参数
1
2 template<typename T>
void assign(T &d, const T& s);
1 2 3 4 | int main() { vector<int> v; assign(v, { 1, 2, 3 }); } |
如果将
原因在N2640中进行了描述:
A {}-list cannot deduce against a plain type parameter
T . For example:
1
2
3
4
5 template<class T> void count(T); // (1).
struct Dimensions { Dimensions(int, int); };
size_t count(Dimensions); // (2).
size_t n = count({1, 2}); // Calls (2); deduction doesn't
// succeed for (1).Another example:
1
2
3
4
5
6
7 template<class T>
void inc(T, int); // (1)
template<class T>
void inc(std::initializer_list< T >, long); // (2)
inc({1, 2, 3}, 3); // Calls (2). (If deduction had succeeded
// for (1), (1) would have been called — a
// surprise.)On the other hand, being able to deduce an
initializer_list forT is attractive to
allow:
1
2
3 auto x = { 1, 1, 2, 3, 5 };
f(x);
g(x);which was deemed desirable behavior since the very beginning of the EWG discussions about
initializer lists.Rather than coming up with a clever deduction rule for a parameter type
T matched with a {}-list (an option we pursued in earlier sketches and drafts of this paper), we now prefer to handle this with a special case for"auto" variable deduction when the initializer is a {}-list. I.e., for the specific case of a variable declared with an"auto" type specifier and a {}-list initializer, the"auto" is deduced as for a functionf(initializer_list< T >) instead of as for a functionf(T) .
得出结论,问题在于,如果我们允许{} -list推断出普通类型的参数
首先,它是您所谓的"这可能是原因的"形式的"推测性解释"。
1 2 3 4 5 6 7 8 9 10 11 12 | #include <initializer_list> struct x{ int a,b,c; }; void f(x){ } int main() { f({1,2,3}); } |
是正确的代码。为了表明它不是
1 2 3 4 5 6 7 8 9 10 11 | #include <initializer_list> struct x{int a,b,c;}; void f(x){ } int main() { auto il = {1, 2, 3}; f(il); } |
错误是:
1 2 | prog.cpp: In function ‘int main()’: prog.cpp:10:9: error: could not convert ‘il’ from ‘std::initializer_list<int>’ to ‘x’ |
现在来问"有什么区别?"
在
在使用功能模板的情况下,他可以确定使用的是其他类型。并且最好避免在模棱两可的情况下发生错误(看起来好像不是C ++风格)。
尤其糟糕的是,如果有1个功能