Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clang does not notice default template parameters

Background

According to the C++ standard, when forward-declaring a template type with default template parameters, each of them can appear in one declaration only. For example:

// GOOD example
template <class T = void>
class Example;    // forward-declaration

template <class T>
class Example {}; // definition
// GOOD example
template <class T>
class Example;    // forward-declaration

template <class T = void>
class Example {}; // definition
// BAD example
template <class T = void>
class Example;    // forward-declaration

template <class T = void> // ERROR: template parameter redefines default argument
class Example {}; // definition

Problem

In my code I have a lot of forward declaration in different files, so it makes sense to put my default parameters in the definition:

// foo.hpp, bar.hpp, baz.hpp, etc.
template <class T>
class Example;
// example.hpp
template <class T = void>
class Example {};

and, as expected, it all works well everywhere... except clang! I narrowed the problem down to this:
In clang, if the class template has default parameters, but they are not declared in the first forward declaration of that class, and when declaring an instance of that class no angle brackets are specified, clang ignores the default parameter and raises an error "no viable constructor or deduction guide for deduction of template arguments of ...".

Example

// GOOD example
template <class T>
class Example;

template <class T = void>
class Example {};

int main() {
    Example e; // error: no viable constructor or deduction guide for deduction of template arguments of 'Example'
}
  • Moving = void to the forward declaration fixes the issue, but is not viable for me since my forward-decls are in different files and I don't know which one will appear first. (Also super problematic since my defaults would be in some obscure file deep in the codebase)
  • Changing Example e; to Example<> e; fixes the issue, but is not viable for me since I'm a library dev and don't want all my users typing <> after my classes.
  • Adding a forward-declaration file example_fwd.hpp with one forward-declaration and including it instead of forward declaring every time fixes the issue, but I would like to avoid this if there is a better solution.

Question

Who is right in this case: clang or the other compilers? Is this a compiler bug? How can I circumvent this issue (apart from partial solutions I described above)? I've found #10147 (and related stackoverflow questions), but it's about template template params and also is marked as fixed over a year ago.

Edit

This looks like a bug, and is now reported on LLVM bugtracker (#40488).

like image 291
andreasxp Avatar asked Jan 24 '19 16:01

andreasxp


1 Answers

I don't know who's right but...

How can I circumvent this issue (apart from partial solutions I described above)?

What about adding the following deduction rule?

Example() -> Example<>;

The following code compile (C++17, obviously) with both g++ and clang++

template <class T>
class Example;

template <class T = void>
class Example {};

Example() -> Example<>;

int main() {
    Example e;
}
like image 107
max66 Avatar answered Oct 05 '22 23:10

max66