samedi 7 mai 2022

Variadic template template wrapper: weird compilers errors, possibly bugs

Over years of template metaprogramming practice, I have encountered all sorts of weird compiler bugs and errors. But with this one, I must say that I am somewhat puzzled. I have no idea which compiler is correct: ccc, clang, msvc, and intel all give different results (and as surprising as it may sound, only intel compiles the code without errors). Even more surprising, it does not rely on any new C++ feature as only C++11 is involved.


The code will speak for itself as it is relatively simple. It only consists of a variadic template template wrapper with a variadic inner entity that can be either a struct or an alias template. And for whatever reason, the alias template version returns an error for some compilers when an instance of it is constructed:

#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...>;
};

And now the test:

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;     // CLANG, MSVC ERROR: WAIT WHAT ?!?!
    ta4 a4;     // GCC, CLANG, MSVC ERROR
    return 0;
}

The code is available on compiler explorer: https://godbolt.org/z/3ndYMWvfs


QUESTION: What is happening? Which compiler is correct? What does the standard say? Is it a compiler bug?

Aucun commentaire:

Enregistrer un commentaire