В случае ошибки замещения, связанной с псевдонимом шаблона (например псевдоним шаблона для отсутствующего члена typename, как в приведенном ниже фрагменте кода), должна ли произойти ошибка?
Clang и gcc, похоже, не согласны с этим:
// some types
struct bar { };
struct foo {
typedef void member_type;
};// template alias
template<class T>
using member = typename T::member_type;template<class T>
void baz(... ) { }
// only works for gcc, clang fails with: no type named 'member_type'
// in 'bar'
template<class T>
void baz( member<T>* ) { }int main(int, char** ) {
baz<bar>(0); // picks first
baz<foo>(0); // picks second
return 0;
}
Таким образом, вопрос: кто прав и почему?
Спасибо 🙂
Согласно Стандартам, ясно, что GCC является правильным, потому что шаблон псевдонима должен быть немедленно заменен, а затем применяется обычный / обычный SFINAE. typename T::member_type
позже, когда T
известен.
Но в настоящее время есть проблема для этого, смотрите http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1554.
Судя по результатам встреч, поведение клангов является желательным: замена T
будет сделано в контексте шаблона псевдонима (хотя во время замены в typename T::member_type
, больше нет ссылки на шаблон псевдонима — на него все равно нужно будет ссылаться как на источник источника шаблона типа, если он так реализован).
Это похоже на другую ситуацию, когда шаблоны отбрасываются во время определения, что может повлиять на семантику создания
template<int I>
void f(int x[I]);
int main() {
f<0>(nullptr);
}
И в этом случае, на мой взгляд, в стандарте нормативно ясно, что параметр немедленно заменяется на int*
и, таким образом, экземпляр работает. Увидеть http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1322 .
Других решений пока нет …