Фактический результат разрешения имен в шаблоне класса отличается от стандарта c ++ 03 - PullRequest
14 голосов
/ 03 октября 2011

Я тестирую код в стандарте c ++ ISO / IEC 14882-03 14.6.1 / 9 в Xcode 4.1 и Visual Studio 2008. Выводы обоих компиляторов отличаются от ожидаемого результата стандарта.

Код вставлен ниже.

#include <stdio.h>
#include <iostream>
using namespace std;

void f(char);

template <class T > void g(T t)
{
    f(1);
    f(T(1));
    f(t);
}

void f(int);
void h()
{
    g(2);
    g('a');
}

void f(int)
{
     cout << "f int" << endl;
}


void f(char)
{
    cout << "f char" << endl;
}


int main() { 
    h();  
    return 0;
}

как описание стандарта. Ожидаемый результат должен быть

f char
f int
f int
f char
f char
f char

Сборка и запуск кода на Xcode 4.1. Вывод как показано ниже. В настройках сборки я попытался изменить «Компилятор для C / C ++ / Object-C» на Apple LLVM Compiler 2.1, Gcc 4.2 и LLVM GCC 4.2. Выходы одинаковые.

f char
f char
f char
f char
f char
f char

Создайте и запустите код в Microsoft Visual Studio 2008. Вывод будет следующим:

f int
f int
f int
f int
f char
f char

Описание (14.6.1 / 9) стандарта приведено ниже.

Если имя не зависит от параметра-шаблона (как определено в 14.6.2), объявление (или набор объявлений) для этого имени должно находиться в области действия в точке, где имя появляется в шаблоне определение; имя привязано к объявлению (или объявлениям), найденному в этой точке, и на эту привязку не влияют объявления, видимые в момент создания экземпляра. [Пример:

void f(char);
template<class T> void g(T t)
{
f(1); // f(char) 
f(T(1)); // dependent 
f(t); // dependent 
dd++; // not dependent
}
void f(int);
double dd;
void h()
{
// error: declaration for dd not found
g(2); // will cause one call of f(char) followed // by two calls of f(int)
g(’a’); // will cause three calls of f(char) 

- конец примера]

Код корректно сформирован для компиляторов, но результаты отличаются. Было бы очень опасно переносить этот код на разные платформы.

Кто-нибудь знает, почему эти компиляторы не следуют стандарту?

Редактировать 10.11.2011

За http://www.open -std.org / jtc1 / sc22 / wg21 / docs / cwg_defects.html # 197 , пример в стандарте неверен. Я тестирую код ниже на Clang и Gcc.

#include <stdio.h>
#include <iostream>
using namespace std;

void f(char);

template <class T > void g(T t)
{
    f(1);
    f(T(1));
    f(t);
}

enum E{ e };

void f(E );
void h()
{
    g(e);
    g('a');
}

void f(E )
{
    cout << "f E" << endl;
}

void f(char)
{
    cout << "f char" << endl;
}

int main() { 
    h();  
    return 0;
}

Вывод, как и ожидалось.

f char
f E
f E
f char
f char
f char

Спасибо

Jeffrey

Ответы [ 3 ]

5 голосов
/ 03 октября 2011

То, с чем вы сталкиваетесь, это тот факт, что Visual Studio не реализует двухфазный поиск .Они только ищут фактическое имя, когда вы создаете экземпляр шаблона.

И на данный момент Microsoft в значительной степени решила, что не заинтересована в поддержке двухфазного поиска.

3 голосов
/ 11 октября 2011

Как отмечалось в первом примере, это экземпляр двухфазного поиска имени, который реализован как в GCC, так и в Clang, а MSVC - нет. И в этом случае и GCC, и Clang верны: на самом деле это неверный стандарт, как отмечается в отчете о дефектах ядра C ++ № 197 . Стандарт C ++ 11 содержит другой пример.

Это одна из наиболее распространенных проблем , которую мы видим при переносе кода в Clang либо из MSVC (который никогда не реализовывал поиск по двухфазному имени), либо из GCC (который не реализовал двухфазное имя до последнего времени единообразно искать).

2 голосов
/ 03 октября 2011

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

Я думаю, что, вероятно, происходит то, что в случае MSVC компилятор оптимизирует лишний проход за счет того, что в конечном итоге получает знания о определенной позже функции, которую не следует использовать в случае не шаблонные звонки. Должен признаться, я не понимаю, как GCC / LLVM в итоге получит результаты, которые они делают, так как результаты - это то, что вы ожидаете как исключение, а не правило.

Полагаю, я бы запечатлел это как ошибку на http://bugreport.apple.com/ и http://connect.microsoft.com/ и посмотрел бы, что они говорят?

...