В своей презентации "С++ и Beyond 2012: Universal References" Скотт неоднократно подчеркивает, что универсальные ссылки обрабатывают/связывают со всем и, таким образом, перегружают функцию, которая уже принимает универсальный ссылочный параметр, не имеет смысла.
У меня не было причин сомневаться в этом, пока я не смешал их с 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 Nov 2012 CTP жалуется на двусмысленность (error C2668: 'foo' : ambiguous call to overloaded function
). Еще более удивительным является то, что gcc-4.7.2, gcc-4.9.0 и clang-3.4 соглашаются на следующий вывод:
initializer list
initializer list
initializer list
universal reference
По-видимому, возможно (с gcc и clang) перегружать функции, принимающие универсальные ссылки с помощью initializer_list
, но при использовании auto + { expr } => initializer_list
-idiom даже имеет значение, берет ли значение initializer_list
по значению или const&
.
По крайней мере, мне это поведение было совершенно неожиданным.
Какое поведение соответствует стандарту? Кто-нибудь знает логику этого?