В C++ 0x SFINAE правила были упрощены таким образом, что любое недопустимое выражение или вводит, который происходит в "прямом контексте" вычета, не приводит к ошибке компилятора, а скорее к отказу вычета (SFINAE).
Мой вопрос - это:
Если я беру адрес перегруженной функции, и он не может быть разрешен, то, что отказ в прямом контексте вычета?
(т.е. действительно ли это - серьезная ошибка или SFINAE, если это не может быть разрешено)?
Вот некоторый пример кода:
struct X
{
// template<class T> T* foo(T,T); // lets not over-complicate things for now
void foo(char);
void foo(int);
};
template<class U> struct S
{
template<int> struct size_map
{ typedef int type; };
// here is where we take the address of a possibly overloaded function
template<class T> void f(T,
typename size_map<sizeof(&U::foo)>::type* = 0);
void f(...);
};
int main()
{
S<X> s;
// should this cause a compiler error because 'auto T = &X::foo' is invalid?
s.f(3);
}
Gcc 4.5 указывает, что это - ошибка компилятора, и лязг выкладывает нарушение утверждения.
Вот еще некоторые связанные вопросы интереса:
FCD-C++ 0x ясно указывают то, что должно произойти здесь?
Находятся компиляторы неправильно в отклонении этого кода?
"Прямой контекст" вычета должен быть определен немного лучше?
Спасибо!
template<class T> void f(T,
typename size_map<sizeof(&U::foo)>::type* = 0);
Это не работает, потому что U
не участвует в дедукции. Хотя U
является зависимым типом, при выводе для f
он рассматривается как фиксированный тип с независимым именем. Вам необходимо добавить его в список параметров f
/* fortunately, default arguments are allowed for
* function templates by C++0x */
template<class T, class U1 = U> void f(T,
typename size_map<sizeof(&U1::foo)>::type* = 0);
. В вашем случае, поскольку U :: foo
не зависит от параметров самого f
, вы получите ошибка при неявном создании экземпляра S
(попробуйте закомментировать вызов, и он все равно не удастся). FCD говорит в 14.7.1 / 1
Неявное создание экземпляра специализации шаблона класса вызывает неявное создание экземпляров объявлений, но не определений или аргументов по умолчанию, функций-членов класса, классов-членов, статических элементы данных и шаблоны элементов;
То есть, если вы неявно создаете экземпляр S
, будет создано следующее объявление шаблона функции
template<class T> void S<X>::f(T,
typename size_map<sizeof(&X::foo)>::type* = 0);
Анализ этого объявления шаблона затем обнаружит, что он не может разрешить ссылку на X :: foo
и вывести ошибку. Если вы добавите U1
, объявление шаблона еще не будет пытаться разрешить ссылку на U1 :: foo
(поскольку U1
является параметром f
), и, таким образом, останется действительным и SFINAE при попытке вызова f
.