За годы практики метапрограммирования шаблонов я столкнулся со всевозможными странными багами и ошибками компилятора. Но с этим, я должен сказать, что я несколько озадачен. Я понятия не имею, какой компилятор правильный: gcc, clang, msvc и intel дают разные результаты (и, как ни удивительно, только intel компилирует код без ошибок). Что еще более удивительно, он не зависит от какой-либо новой функции C++, поскольку задействован только C++11.
Код будет говорить сам за себя, так как он относительно прост. Он состоит только из оболочки шаблона шаблона с переменным числом аргументов и внутреннего объекта с переменным числом переменных, который может быть либо структурой, либо шаблоном псевдонима. И по какой-то причине версия шаблона псевдонима возвращает ошибку для некоторых компиляторов при создании его экземпляра:
#include <type_traits>
template <class T1, class T2, class T3>
struct ternary {};
template <template <class...> class Template, class... Types>
struct template_struct {
template <class... Args>
struct type: Template<Types..., Args...> {};
};
template <template <class...> class Template, class... Types>
struct template_alias {
template <class... Args>
using type = Template<Types..., Args...>;
};
А теперь тест:
int main(int, char**) {
using ts0 = template_struct<ternary>; // OK
using ts1 = template_struct<ternary, bool>; // OK
using ts2 = template_struct<ternary, bool, char>; // OK
using ts3 = template_struct<ternary, bool, char, int>; // OK
using ts4 = template_struct<ternary, bool, char, int, double>; // OK
ts0 s0; // OK
ts1 s1; // OK
ts2 s2; // OK
ts3 s3; // OK
ts4 s4; // OK
using ta0 = template_alias<ternary>; // OK
using ta1 = template_alias<ternary, bool>; // OK
using ta2 = template_alias<ternary, bool, char>; // OK
using ta3 = template_alias<ternary, bool, char, int>; // OK
using ta4 = template_alias<ternary, bool, char, int, double>; // OK
ta0 a0; // OK
ta1 a1; // OK
ta2 a2; // OK
ta3 a3; // GCC, INTEL => OK | CLANG, MSVC => ERROR: WAIT WHAT ?!?!
ta4 a4; // INTEL => OK | GCC, CLANG, MSVC => ERROR
return 0;
}
Код доступен в проводнике компилятора: https://godbolt.org/z/3ndYMWvfs
ВОПРОС: Что происходит? Какой компилятор правильный? Что говорит стандарт? Это ошибка компилятора?





Все компиляторы правы, два не пройденных теста - это неправильно сформированный отчет о недоставке ("Диагностика не требуется").
Случай аргументов > 3 является неправильным отчетом о недоставке из-за [temp.res.general]/6.1:
The program is ill-formed, no diagnostic required, if:
— no valid specialization can be generated for a template ... and the template is not instantiated, ...
Случай аргументов == 3 является неправильным отчетом о недоставке из-за [temp.res.general]/6.3:
The program is ill-formed, no diagnostic required, if:
— every valid specialization of a variadic template requires an empty template parameter pack ...
Два теста template_struct<ternary, ...> кажутся законными, потому что вы можете специализировать struct type на что-то действительное, и я не сразу вижу правило, согласно которому должна быть хотя бы одна действительная специализация основного (неспециализированного) шаблона.
@ Винсент Нет, я правильно понял исходные комментарии, и мой ответ остается прежним. «Неправильно сформированный отчет о недоставке» (он же «диагностика не требуется») означает, что код недействителен, но не выдавать ошибку на нем разрешено.
Посмотрите отредактированные комментарии, которые я сделал к коду, чтобы было понятнее: все компиляторы не могут быть правы одновременно, потому что их вывод отличается. GCC и INTEL подходят для случая == 3, а CLANG и MSVC — НЕ.