псевдонимы шаблонов и sfinae

В случае сбоя подстановки, связанного с псевдонимом шаблона (например, псевдонимом шаблона для отсутствующего имени типа члена, как показано во фрагменте кода ниже), должна ли возникать ошибка?

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;
}

Так вот вопрос: кто прав и почему?

Спасибо :-)


person max    schedule 05.12.2012    source источник
comment
Что говорит clang -v? Транк Clang 3.3 отлично компилирует код.   -  person Xeo    schedule 05.12.2012
comment
Debian clang версии 3.1-8 здесь, похоже, мне просто нужно подождать. Спасибо за ваш отзыв !   -  person max    schedule 05.12.2012
comment
Можете ли вы избавиться от псевдонима шаблона, просто чтобы немного упростить ситуацию?   -  person David    schedule 05.12.2012
comment
@Dave: весь смысл вопроса был в использовании псевдонимов, так что...   -  person Xeo    schedule 05.12.2012
comment
@ Ксео, о, извини. Я только посмотрел на код и подумал, что это как раз про SFINAE.   -  person David    schedule 06.12.2012


Ответы (1)


Согласно Стандартам, это явно GCC, потому что шаблон псевдонима должен быть немедленно заменен, а затем обычный/обычный SFINAE применяется к typename T::member_type позже, когда T известен.

Но в настоящее время для этого существует проблема, см. http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1554.

Судя по результатам встреч, представляется желательным поведение clangs: замена 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 .

person Johannes Schaub - litb    schedule 05.12.2012
comment
Судя по результатам встреч, кажется, что поведение clang желательно - не убьет ли это полностью любой псевдоним EnableIf? кажется крайне нежелательным, чтобы шаблоны псевдонимов не генерировали программные ошибки SFINAE. - person Xeo; 05.12.2012
comment
@Xeo да, это было бы плохо. И на самом деле, clang trunk принимает псевдоним EnableIf, поэтому мне кажется, что поведение, которое наблюдал автор вопроса, было просто ошибкой clang, и что сводка проблемы на сайте wg21 просто сбивает с толку (ИМХО). - person Johannes Schaub - litb; 05.12.2012
comment
Да, я был сбит с толку, так как я уже прокомментировал, что ствол отлично компилирует код. - person Xeo; 05.12.2012