Почему MSVC не удается скомпилировать эту функцию шаблона?

У меня возникла проблема с переносом некоторого кода в MSVC, что меня озадачило. Насколько мне известно, код должен быть законным, а Clang просто компилирует его.

Я сузил его до следующего:

enum E {
    x
};

template <typename T>
struct traits {
    static const E val = x;
};

template <E e>
struct S {
    S(){};
};

template <typename T>
S<traits<T>::val> foo(T t);

int main() {
    char c = 0;
    foo(c);
}

Обратите внимание, что после компиляции ожидается, что код даст ошибку компоновщика (я удалил определение функции foo, чтобы сохранить образец минимальным), но он должен скомпилировать, насколько я знаю,

Однако MSVC дает мне эту ошибку:

ошибка C2893: не удалось специализировать шаблон функции "S:: val > foo (T)"

Итак, мой вопрос:

  • является MSVC, если он ошибочно отвергает код? (и если да, то почему?)
  • Если нет, может ли кто-нибудь сузить то, что он делает неправильно? Как и в случае, это языковая функция, которую они вообще не реализуют (например, поиск двухфазных имен для шаблонов) или "просто" простая ошибка при реализации функции, которую они утверждают, что она поддерживает?

Я воспроизвел проблему на VС++ 2010 и 2012.

Ответ 1

После запуска нескольких тестов, это, похоже, ошибка компилятора в MSVC. Несмотря на то, что он отлично работает с GCC, MSVC дает загадочную и бесполезную ошибку компилятора (идентичную тем, которые заданы в вашем вопросе), когда вы пытаетесь использовать traits<T>::val внутри параметров шаблона для возврата S< E e >.

Самое смешное, когда вы меняете S< E e >, чтобы вместо этого взять целое число, оно работает. Рассмотрим этот пример, идентичный вашему, с различными именами:

enum E {
    x
};

template <typename T>
struct traits {
    static const E val = x;
};

template <E e>
struct S {
    S(){};
};

template <typename T>
S< traits<T>::val > tricky(T t) {
    return S< traits<T>::val > ();
};

int main() {
    char thiskidwhowalksaround = 0;
    S<x> s = tricky( thiskidwhowalksaround );
}

Теперь просто изменим одну вещь:

template <int e> // int instead of E
struct S {
    S(){};
};

Программа затем компилирует (ссылки и работает) безупречно для меня. Если вы также вернетесь к оригиналу, а затем передайте значение E напрямую, например:

template <typename T>
S< x > tricky(T t) { 
// ^ here
    return S< x > (); // <-- here
};

Затем программа компилирует файл. MSVC имеет проблему, когда он кусает пыль при попытке сделать следующее:

traits<T>::val

где val - любой вид перечисления. Я на 99% уверен, что это недостаток в компиляторе. Это, по-видимому, отлично сформированный С++, поэтому я не могу сказать, что GCC делает что-то неправильно или расширяет-y, имея исходный фрагмент кода. Таким образом, лучшее, что я могу почерпнуть, заключается в том, что MSVC не хватает в надежности компилятора по сравнению с его сверстниками, но опять же.

Вы можете перестать читать здесь, потому что теперь я собираюсь немного рассказать о компиляторе MSVC.

begin<rant> Это не то, что команда VС++ плоха или что С++ плохой, но из того, что я собираю команда компилятора и стандартные библиотеки в Microsoft - на момент написания - крошечный по сравнению с другими ведомства. Меня раздражает, что такой фундаментальный и важный язык и часть ядра MS-индустрии обладают такой сравнительно небольшой рабочей силой, что он не может идти в ногу с тем, что - за короткое время жизни - я считаю одним из самых медленных движущихся стандартов в мире. Я, конечно, не сбиваю людей, которые работают в команде VС++, но я глубоко озадачен тем, почему их больше не работает над тем, чтобы С++ не только ускорялся, но и улучшал работу компилятора и так же хорошо, как и другие продуктов. end<rant>