Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template template argument causes compiler error under Clang but not GCC [duplicate]

While helping with problem noted in too many template parameters in template template argument a question arose in my head: which compiler is right about the compilation in this case:

template <template <typename, typename> class Op>
class Function
{
};

template <typename A, typename B, bool is_f = std::is_floating_point<A>::value || std::is_floating_point<B>::value > struct Operator;

template <typename A, typename B>
struct Operator<A, B, false>
{};


template <typename A, typename B>
struct Operator<A, B, true>
{};

using FunctionOperator = Function<Operator>;


int main(int argc, char * argv[]){
    std::cout << "hi!\n";
    return 0;
}

GCC 7+ compiles it with no errors. Clang 6 and later gives errors showing that there is a problem with Operator template passed as template argument:

tmp.cpp:19:35: error: template argument has different template parameters than its corresponding template parameter
using FunctionOperator = Function<Operator>;
                                  ^
tmp.cpp:8:1: note: too many template parameters in template template argument
template <typename A, typename B, bool is_f = std::is_floating_point<A>::value || std::is_floating_point<B>::value > struct Operator;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tmp.cpp:3:11: note: previous template template parameter is here
template <template <typename, typename> class Op>
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

Obviously, it treats it as 3-arguments template even though the default third argument is supplied. So here is the question, which of the compilers is right? Does standard say anything about such situations?

PS I do not need a workaround for these kinds of problems as it is pretty simple. I just want to know "who is right"

like image 564
bartop Avatar asked Jul 11 '18 11:07

bartop


1 Answers

Gcc is correct. Clang seems not in accordance with C++17.

Since C++17 (CWG 150), the default template arguments are allowed for a template template argument to match a template template parameter with fewer template parameters.

template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template <class ...Types> class C { /* ... */ };

template<template<class> class P> class X { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK in C++17 after CWG 150
         // Error earlier: not an exact match
X<C> xc; // OK in C++17 after CWG 150
         // Error earlier: not an exact match

Operator has 3 template parameters, the 3rd one has default value, then it could be used as the argument for template template parameter Op, even it only expects two template parameters.

like image 133
songyuanyao Avatar answered Oct 07 '22 04:10

songyuanyao