Фактический результат разрешения имен в шаблоне класса отличается от стандарта C++ 03

Я тестирую код в стандарте 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, пример в стандарте неверен. Я тестирую код ниже на 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

Спасибо,

Джеффри

3 ответа

Решение

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

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

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

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

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

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

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

Другие вопросы по тегам