Если адрес функции не может быть разрешен при выводе, это SFINAE или ошибка компилятора? - PullRequest
22 голосов
/ 23 мая 2010

В 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 утверждает, что это ошибка компилятора, и clang выплевывает нарушение утверждения.

Вот еще несколько связанных вопросов:

В FCD-C ++ 0x четко указано, что должно происходить здесь?
Являются ли компиляторы неправильными в отклонении этого кода?
Нужно ли определять «непосредственный контекст» дедукции чуть лучше?

Спасибо!

1 Ответ

28 голосов
/ 23 мая 2010
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<X> (попробуйте закомментировать звонок, и он все равно должен потерпеть неудачу).FCD говорит по адресу 14.7.1/1

Неявное создание экземпляра специализации шаблона класса вызывает неявное создание экземпляров объявлений, но не определений или аргументов по умолчанию, функций-членов класса, классов-членов,члены статических данных и шаблоны элементов;

То есть, если вы неявно создадите экземпляр S<X>, будет создано следующее объявление шаблона функции

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называться.

...