Вычисление аргумента шаблона шаблона и параметры шаблона по умолчанию

Следующий удаленный код не работает с последним clang++ 5, но принят 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);
}

Он не работает со следующими сообщениями об ошибке:

<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;
    ^

Однако, если я перенулю параметр шаблона по умолчанию =int из определения шаблона класса в декларацию вперед, все работает отлично (U выводится на int как ожидалось), как если бы только шаблон по умолчанию в переднем объявлении принимался во внимание при создании набор шаблонов вымышленных функций, используемых гидами дедукции.

Я попытался прочесть стандартную формулировку, но не смог извлечь из этого ничего для этого конкретного случая. Является ли только параметр шаблона по умолчанию в объявлении вперед предполагаемым поведением при создании шаблонов вымышленных функций или это ошибка компилятора?

Ответы

Ответ 1

Это не цитата из Стандарта per se 1 но я достаточно уверенно считаю это ответом.

Согласно cppreference, по аргументам шаблона по умолчанию:

Аргументы шаблона по умолчанию, которые появляются в объявлениях и определении, объединены аналогично аргументам аргументов по умолчанию:

template<typename T1, typename T2 = int> class A;
template<typename T1 = int, typename T2> class A;
// the above is the same as the following:
template<typename T1 = int, typename T2 = int> class A;

Но тот же параметр не может быть дважды задан аргументами по умолчанию в той же области

template<typename T = int> class X;
template<typename T = int> class X {}; // error

Это подразумевает неявное правило: аргументу типа шаблона можно присвоить тип по умолчанию в объявлении шаблона или определении шаблона взаимозаменяемо.

Поведение clang++ 5 показывает, что это определенно ошибка.


1) Предоставлено пользователем Oliv:

[temp.param]/10

Набор аргументов-шаблонов по умолчанию, доступных для использования, получается путем слияния аргументов по умолчанию из всех предшествующих объявлений шаблона таким же образом, как и аргументы функции по умолчанию ([dcl.fct.default]). [ Пример:

template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;

эквивалентно

template<class T1 = int, class T2 = int> class A;

- конец примера]