The following stripped down code doesn't work with the latest clang++5 but is accepted by g++7:
template<typename Wrapped, typename U>
struct wrapper;
template<typename Wrapped, typename U=int>
struct wrapper
{
wrapper() = default;
// Automatic deduction guide
constexpr explicit wrapper(Wrapped) noexcept {}
};
int main()
{
struct {} dummy;
constexpr auto wrapped = wrapper(dummy);
}
It fails with the following error messages:
<source>:18:30: error: no viable constructor or deduction guide for deduction of template arguments of 'wrapper'
constexpr auto wrapped = wrapper(dummy);
^
<source>:12:24: note: candidate template ignored: couldn't infer template argument 'U'
constexpr explicit wrapper(Wrapped) noexcept {}
^
<source>:4:8: note: candidate template ignored: could not match 'wrapper<Wrapped, U>' against '(anonymous struct at <source>:17:5)'
struct wrapper;
^
<source>:9:5: note: candidate function template not viable: requires 0 arguments, but 1 was provided
wrapper() = default;
^
However if I move the default template parameter =int
from the class template definition to the forward declaration, everything works perfectly (U
being deduced to int
as expected), as if only the default template parameter in the forward declaration was taken into account when create the set of fictional function templates used by deduction guides.
I tried to read the standard wording but couldn't get much out of it for this specific case. Is only taking the default template parameter in the forward declaration the intended behaviour when generating the fictional function templates, or is this a compiler bug?
This is not a quote of the Standard per se1, but I feel confident enough to consider it an answer.
According to cppreference, on Default template arguments:
This implies an implicit rule: A template type argument can be given a default type in the template declaration or template definition interchangeably.
The behavior clang++5 exhibits is definitly a bug.
1) Provided by user Oliv: