Типовое разрешение в случаях двусмысленности - PullRequest
0 голосов
/ 16 ноября 2011

Я играл с Visual Studio и шаблонами.

Рассмотрим этот код

struct Foo
{
  struct Bar
  {
  };

  static const int Bar=42;
};

template<typename T>
void MyFunction()
{
  typename T::Bar f;  
}

int main()
{
    MyFunction<Foo>();
    return 0;
}

Когда я компилирую это Visual Studio 2008 и 11, я получаю следующую ошибку

error C2146: syntax error : missing ';' before identifier 'f'

Правильно ли Visual Studio в этом отношении? Код нарушает какие-либо стандарты?

Если я изменю код на

struct Foo
{
  struct Bar
  {
  };

  static const int Bar=42;
};


void SecondFunction( const int& )
{
}

template<typename T>
void MyFunction()
{
  SecondFunction( T::Bar ); 
}

int main()
{
    MyFunction<Foo>();
    return 0;
}

компилируется без каких-либо предупреждений. В Foo :: BLAH член предпочтительнее типа в случае конфликтов?

РЕДАКТИРОВАТЬ Тесты на G ++ 4.2.1

struct Foo
{
  static const int Bar=42;
};


void SecondFunction(const int& x)
{
}

template<typename T>
void MyFunction()
{
  int x = Foo::Bar;
}

int main()
{
  MyFunction<Foo>();
  return 0;
}

компилирует ОК.

struct Foo
{
  static const int Bar=42;
};


void SecondFunction(const int& x)
{
}

template<typename T>
void MyFunction()
{
  SecondFunction(T::Bar);
}

int main()
{
  MyFunction<Foo>();
  return 0;
}

дает мне эти ошибки

Неопределенные символы: "Foo :: Bar", по ссылке с: void MyFunction () в cck498aS.o ld: символ (ы) не найден collect2: ld вернул 1 статус выхода

Ответы [ 2 ]

3 голосов
/ 16 ноября 2011

Вы видите эффект не очень известного правила, которое существует для совместимости с Си.В C, в отличие от C ++, если вы определяете тип как struct X или enum X, вы не вводите имя X в соответствующее пространство имен, но должны ссылаться на тип как struct X.По этой причине в C вы можете дополнительно определить «X» как нечто иное, не вызывая противоречивых определений.Теперь в C ++ struct X вводит имя X в соответствующую область.Поэтому любое другое определение X будет помечено как двойное определение.Однако было сочтено важным иметь возможность включать заголовки C, где эта проблема часто возникает.Поэтому было введено специальное правило, что всякий раз, когда у вас обоих есть определение типа (не typedef) для X и другое определение для X, это не приводит к ошибке, но X относится к определению не-типаи чтобы получить определение типа, вы должны поставить перед ним ключевое слово соответствующего типа (например, struct X, emum X или class X).

В вашем случае это означает, что Fooсодержит тип с именем class Bar и статический констант int с именем Bar, но без типа с именем Bar.Обратите внимание, что шаблон здесь не нужен;простое глобальное объявление Bar::Foo foo; также должно завершиться ошибкой.

3 голосов
/ 16 ноября 2011

В C ++ именованные объекты попадают в один из трех отдельных онтологических уровней: значения , типы и шаблоны .

Если зависимое имя имеет неизвестный уровень, то вы должны сообщить компилятору, что это такое:

  • Если вы ничего не говорите, это значение.

  • Если вы говорите typename, это тип.

  • Если вы скажете template, это шаблон.

Таким образом, T::Bar, будучи зависимым именем в шаблоне MyFunction, автоматически подразумевает ссылку на значение, следовательно, int member Foo::Bar. С другой стороны, в первом примере typename T::Bar действительно относится к элементу type Foo::Bar.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...