2016-11-10 10 views
3

Рассмотрим следующий код:typename, члены типа и члены не-типа: это действительный код?

struct S { 
    struct type {}; 
    type type; 
}; 

int main() { 
    typename S::type t; 
    (void) t; 
} 

Помимо того факта, что далеко от того, чтобы быть хорошей идеей, я экспериментировал, прочитав другой вопрос здесь на SO.
я обнаружил, что фрагмент кода выше compiled with no errors by GCC и это rejected by clang 3.9 со следующей ошибкой:

error: typename specifier refers to non-type member 'type' in 'S'

Я подозреваю, что лязг является правильным в данном случае и GCC является неправильным (на самом деле, я открываю вопрос к последний).
Правильно ли это заключение или является допустимым использованием typename?


Примечание: Я не спрашиваю, как его решить, я знаю, как это сделать. Я спрашиваю только, является ли этот код действительным или нет.

+0

старше НКУ как 4.4.7 отклонит его тоже: http://melpon.org/wandbox/permlink/Oh2Rp4jWjGPIoIwv – marcinj

+1

»не мог t найти что-нибудь в стандарте о законности этого. Тем не менее, 'typename' упоминается только в отношении шаблонов, так что, возможно, это нарушение по духу? Независимо от того, правильный и стандартный способ решения такой конкретной двусмысленности, похоже, является 'struct S :: type t;' – StoryTeller

+2

@marcinj. Это похоже на то, что GCC 4.4.7 не реализует [CWG 382: Allow 'typename' outside шаблонов] (http://wg21.link/cwg382). – cpplearner

ответ

7

[temp.res]/4:

The usual qualified name lookup is used to find the qualified-id even in the presence of typename .

То есть, в отличие от случая с разработан для типа Тендерный с, поиск имени в данном случае не игнорировать имена не типа.

[temp.res]/3:

If the qualified-id in a typename-specifier does not denote a type or a class template, the program is ill-formed.

Так данная программа плохо сформированным.

[temp.res]/4 также есть пример этого:

struct A { 
    struct X { }; 
    int X; 
}; 
struct B { 
    struct X { }; 
}; 
template<class T> void f(T t) { 
    typename T::X x; 
} 
void foo() { 
    A a; 
    B b; 
    f(b);    // OK: T::X refers to B::X 
    f(a);    // error: T::X refers to the data member A::X not the struct A::X 
} 
+0

Но тип 'S :: type' является типом. –

+0

@GillBates 'S :: type' - это имя типа и имя не-типа, а имя типа не скрывает имя типа. – cpplearner

+0

Это разрешение имен шаблонов, хотя в вопросе OP нет никого, я не думаю, что можно сказать, что правила одинаковы. –