11

Consider the following code:

template<typename T>
struct A { };

// same as A, but with one extra defaulted parameter
template<typename T, typename F = int>
struct B { };

template<template<typename> typename T>
T<int> build() { return {}; }

int main()
{
    build<A>();  // works in gcc and clang
    build<B>();  // works in gcc, does not work in clang
}

g++ (7.3.0) compiles the code just fine, however, clang++ (5.0.1) emits the following:

example.cpp:14:5: error: no matching function for call to 'build'
    build<B>();  // works in gcc, does not work in clang
    ^~~~~~~~
example.cpp:9:8: note: candidate template ignored: invalid
      explicitly-specified argument for template parameter 'T'
T<int> build() { return {}; }

Which of the compilers is right?


Note: The important line is obviously:

template<template<typename> typename T>

Because both compilers are satisfied with:

template<template<typename...> typename T>

So the question is whether default values should be considered when passing template template arguments.

max66
  • 65,235
  • 10
  • 71
  • 111
Floop
  • 451
  • 4
  • 10
  • 3
    Fail on c++14, succeed with C++17 with gcc: [Demo](http://coliru.stacked-crooked.com/a/ed95cc1d639efbc3). – Jarod42 Feb 06 '18 at 14:28
  • 2
    A far I know, your code is correct starting from C++17 thanks to [P0522](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0522r0.html), wrong before. – max66 Feb 06 '18 at 14:34
  • @max66 Thank you. Can you make it a full answer? It just seems that clang has not implemented [P0522](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0522r0.html) yet. – Floop Feb 06 '18 at 14:38
  • I copy/pasted the sample code to Wandbox and tried to compile with `clang HEAD 7.0.0` and `C++2a`. The output is similar to that in the question. [**Life demo**](https://wandbox.org/permlink/v8u4kxLzzhIeHfDO) – Scheff's Cat Feb 06 '18 at 15:03
  • @Floop - done; with a little improvement. – max66 Feb 06 '18 at 16:58
  • Maybe a duplicate of [this question](https://stackoverflow.com/questions/19390236/template-template-parameters-and-default-arguments), or [this question](https://stackoverflow.com/questions/5301706/default-values-in-templates-with-template-arguments-c). – xskxzr Feb 06 '18 at 17:04
  • ... or [this one](https://stackoverflow.com/q/44726767/2069064) or [this one](https://stackoverflow.com/q/47731088/2069064) or [this one](https://stackoverflow.com/q/48446983/2069064) – Barry Feb 06 '18 at 17:45

1 Answers1

7

As far I know, your code is correct starting from C++17, wrong before.

This according P0522R0, that is part of new standard, where I see an example that is very, very similar to your code (see "overview"):

template <template <typename> class> void FD();
template <typename, typename = int> struct SD { /* ... */ };
FD<SD>();  // OK; error before this paper (CWG 150)

According the compiler support tables in ccpreference, g++ support P0522R0 from version 7, clang++ from version 4. So both compiler should support your code.

But looking the table in this page, the support for llvm (clang) 5 is defined "partial" and, according a note,

(12): Despite being the the resolution to a Defect Report, this feature is disabled by default in all language versions, and can be enabled explicitly with the flag -frelaxed-template-template-args in Clang 4 onwards. The change to the standard lacks a corresponding change for template partial ordering, resulting in ambiguity errors for reasonable and previously-valid code. This issue is expected to be rectified soon.

So, at your risk, you can try with the flag -frelaxed-template-template-args.

max66
  • 65,235
  • 10
  • 71
  • 111