7

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"

Keyur Ramoliya
  • 1,900
  • 2
  • 16
  • 17
bartop
  • 9,971
  • 1
  • 23
  • 54

1 Answers1

8

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.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • I don't see why some people (like Google's Android folks) force a severely flawed, apparently useless C++ implementation like Clang despite mankind has a working one... – Géza Török Nov 19 '19 at 12:41