Clang vs MSVC: обработка прототипов шаблонных функций

Ниже приведен фрагмент тестового кода, и я сравниваю результат компиляции с MSVC и Clang соответственно. Вывод каждого компилятора показан ниже. MSVC делает вид, что декларация неиспользуемого шаблона даже не существует. Clang производит ошибку. Вопрос в том, какой компилятор здесь наиболее стандартен?

Я видел устаревший производственный код, который опирается на поведение MSVC, и я не уверен, можно ли продолжать его использовать.

class S
{
    struct P {};
};

template<typename T>
S::P Bat(T);

Скомпилируется в MSVC10:

E:\clangbuild\bin\Release>cl /c /nologo test.cpp
test.cpp

Производит ошибку в Clang:

E:\clangbuild\bin\Release>clang++ test.cpp
test.cpp:9:4: error: 'P' is a private member of 'S'
S::P Bat(T);
   ^
test.cpp:5:9: note: implicitly declared private here
struct P {};
        ^
1 error generated.

Ответ 1

Это не удается из-за поиска двухфазного имени в С++.

В первой фазе, когда шаблон сначала анализируется, задолго до его создания, компилятор анализирует шаблон и ищет все не зависящие имена. S::P - это необязательное имя, поэтому компилятор пытается найти его, но он не работает, потому что он является конфиденциальным.

В фазе 2, когда экземпляр шаблона создается, компилятор будет искать любые зависимые имена, которые могут варьироваться от шаблона к шаблону.

Clang довольно строго соответствует поиску двухфазных имен. Тем не менее, MSVC имеет модель синтаксического анализа шаблонов, которая задерживает почти каждый поиск времени создания, что является частью фазы 2. Эта задержка - это то, почему ваш пример будет скомпилирован с MSVC (который не соответствует требованиям), а не в clang. Вот ссылка на дополнительную информацию:

Страшный двухфазный поиск имени

Кроме того, здесь представлены разделы из стандарта С++, где описывается двухфазный поиск.

14.6.8:

При поиске объявления имени, используемого в шаблоне определение, обычные правила поиска (3.4.1, 3.4.2) используются для не зависящие от имени имена. Поиск имен, зависящих от шаблона параметры откладываются до тех пор, пока не будет известен фактический аргумент шаблона.

14.6.9:

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

Затем применяется часть поиска по имени 3.4:

Правила доступа (раздел 11) рассматриваются только после поиска имени и (если применимо). Только после поиска имени, разрешения перегрузки функции (если применимо) и проверка доступа прошла успешно, это атрибуты, введенные имена имен, используемые далее в обработке выражений (раздел 5).

Из этого ясно видно, что ваша программа плохо сформирована. Единственное, что стандартное состояние следует отложить до момента создания, это поиск зависимого имени. Не зависящие имена проходят обычный поиск имен, который включает в себя правила доступа.

Ответ 2

Компилятор действительно необходим для проверки любого искаженного синтаксиса непроинформированных объявлений шаблонов. Любая дополнительная семантическая оценка должна выполняться только при создании экземпляра шаблона.

Так как S:: P действительно является типом, который действителен для возврата из функции, они оба одинаково совместимы.