通用引用和std :: initializer_list [英] Universal references and std::initializer_list
问题描述
在他的C ++ and Beyond 2012:Universal References介绍中,Scott反复强调,通用引用处理/绑定所有内容,因此重载了一个已经采用通用引用参数的函数没有意义。
我没有理由怀疑,直到我与 std :: initializer_list
混合。
In his "C++ and Beyond 2012: Universal References" presentation, Scott repeatedly stresses the point, that universal references handle/bind to everything and thus overloading a function that already takes a universal reference parameter does not make sense.
I had no reason to doubt that until I mingled them with std::initializer_list
.
是一个简短的例子:
#include <iostream>
#include <initializer_list>
using namespace std;
template <typename T>
void foo(T&&) { cout << "universal reference" << endl; }
template <typename T>
void foo(initializer_list<T>) { cout << "initializer list" << endl; }
template <typename T>
void goo(T&&) { cout << "universal reference" << endl; }
template <typename T>
void goo(initializer_list<T> const&) { cout << "initializer list" << endl; }
int main(){
auto il = {4,5,6};
foo( {1,2,3} );
foo( il );
goo( {1,2,3} );
goo( il );
return 0;
}
奇怪的是,VC11 11月2012 CTP抱怨歧义( error C2668:'foo':对重载函数的模糊调用
)。更令人惊讶的是,gcc-4.7.2,gcc-4.9.0和clang-3.4同意以下输出:
Oddly enough, VC11 Nov 2012 CTP complains about ambiguity (error C2668: 'foo' : ambiguous call to overloaded function
). Yet even more suprising is, that gcc-4.7.2, gcc-4.9.0 and clang-3.4 agree on the following output:
initializer list
initializer list
initializer list
universal reference
所以显然有可能使用 initializer_list
s,但是当使用 auto + {expr} = > initializer_list
-idiom它是否需要 initializer_list
by value或 const&
。
至少对我来说,行为是完全令人惊讶的。
哪些行为符合标准?
So apparently it is possible (with gcc and clang) to overload functions taking universal references with initializer_list
s but when using the auto + { expr } => initializer_list
-idiom it does even matter whether one takes the initializer_list
by value or by const&
.
At least to me that behavior was totally surprising.
Which behavior conforms to the standard? Does anyone know the logic behind that?
推荐答案
这里是crux:从一个braced-init-列表中减去一个类型c $ c> {expr ...} )不适用于模板参数,只有 auto
。使用模板参数,您会得到一个扣除失败,并且重载被删除考虑。这导致第一个和第三个输出。
Here's the crux: Deducing a type from a braced-init-list ({expr...}
) doesn't work for template arguments, only auto
. With template arguments, you get a deduction failure, and the overload is removed from consideration. This leads to the first and third output.
无论是否使用
initializer_list
按价值或const&
foo
:对于任何 X
,两个重载 X
和 X&
参数对于左值参数来说是不明确的 - 两者都是同样可行的(对于 X
vs X&&&&&&&
for rvalues)。
foo
: For any X
, two overloads taking X
and X&
parameters are ambiguous for an lvalue argument - both are equally viable (same for X
vs X&&
for rvalues).
struct X{};
void f(X);
void f(X&);
X x;
f(x); // error: ambiguous overloads
然而,部分排序规则在这里(§14.5.6.2)并且采用通用 std :: initializer_list
的函数比通用类型
However, partial ordering rules step in here (§14.5.6.2), and the function taking a generic std::initializer_list
is more specialized than the generic one taking anything.
goo
:对于两个重载 X&
和 X const& / code>参数和
X&
参数,第一个是更可行的,因为第二个重载需要 从 X&
到 X const&
(§13.3.3.1.2/ 1表12和§ 13.3.3.2/3第三个子项目符号)。
goo
: For two overloads with X&
and X const&
parameters and a X&
argument, the first one is more viable because the second overload requires a Qualification conversion from X&
to X const&
(§13.3.3.1.2/1 Table 12 and §13.3.3.2/3 third sub-bullet).
这篇关于通用引用和std :: initializer_list的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!