Почему я не могу использовать std::unique_ptr в качестве аргумента класса template‹class›?

Этот код:

#include <memory>

template <template <typename> class Ptr>
class A { Ptr<int> ints; };

using B = A<std::unique_ptr>;

выдает следующую ошибку (с GCC 6.3):

a.cpp:6:28: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class> class Ptr> class A’
 using B = A<std::unique_ptr>;
                            ^
a.cpp:6:28: note:   expected a template of type ‘template<class> class Ptr’, got ‘template<class _Tp, class _Dp> class std::unique_ptr’

Теперь я могу обойти это, например:

template <typename T>
using plugged_unique_ptr = std::unique_ptr<T>;
using B = A<plugged_unique_ptr>;

но почему я должен? Я имею в виду, почему компилятор не желает «подключить» второй параметр шаблона std::unique_ptr к его значению по умолчанию и разрешить использование std::unique_ptr в качестве аргумента шаблона для A?


person einpoklum    schedule 16.07.2018    source источник
comment
Обратите внимание, что он должен компилироваться с C++17.   -  person HolyBlackCat    schedule 16.07.2018
comment
@HolyBlackCat, можете ли вы указать мне причину, по которой C ++ 17 заставляет это работать?   -  person rubenvb    schedule 16.07.2018
comment
@rubenvb На этой странице есть некоторые пояснения.   -  person HolyBlackCat    schedule 16.07.2018
comment
@HolyBlackCat Я предполагаю, что вы хотели сказать этот бит на этой странице: чтобы сопоставить аргумент шаблона шаблона A с параметром шаблона шаблона P, каждый из параметров шаблона A должен точно соответствовать соответствующим параметрам шаблона P (до C++ 17) P должен быть не менее специализированным, чем A (начиная с C++17)   -  person rubenvb    schedule 16.07.2018
comment
Возможный дубликат параметра шаблона шаблона и значений по умолчанию   -  person Arne Vogel    schedule 25.07.2018


Ответы (3)


Потому что параметры шаблона шаблона должны точно совпадать. Это означает, что аргумент шаблона по умолчанию здесь не актуален. Обратите внимание, что расширение вашего аргумента шаблона шаблона до двух аргументов шаблона будет работать только случайно: реализации разрешено добавлять больше аргументов шаблона, чем определено стандартом, и некоторые часто делают это в случае SFINAE вокруг стандартных контейнеров.

Это также основная причина, по которой я обычно советую не использовать какие-либо аргументы шаблона шаблона, а вместо этого просто использовать простое имя типа шаблона. Если вам нужен доступ к вложенным типам шаблонов, предоставьте внутренние средства доступа в строке, например. value_type или внешние средства доступа, такие как tuple_element, чтобы получить к ним доступ внутри шаблона.


Примечание. Это, по-видимому, изменилось в C++17, где сопоставление больше не является точным, а немного упрощенным, но более сложным. Тем не менее, я бы все же советовал не использовать шаблонные параметры шаблона вообще.

person rubenvb    schedule 16.07.2018
comment
Иногда они вам нужны, если вы хотите применить несколько аргументов внутреннего шаблона. - person einpoklum; 16.07.2018
comment
@einpoklum Я уверен, что иногда они вам нужны, но я не уверен, что означает применение нескольких аргументов внутреннего шаблона. Не могли бы вы привести пример? - person rubenvb; 16.07.2018
comment
@einpoklum Как очевидное может ускользнуть от вас. Спасибо, что нашли время :). - person rubenvb; 16.07.2018

std::unique_ptr имеет второй аргумент шаблона со значением по умолчанию, поэтому template <typename> class Ptr не соответствует std::unique_ptr

template <typename...> class Ptr будет работать

cppreference

person Tyker    schedule 16.07.2018
comment
Не совсем отвечает на мой вопрос, но это умный обходной путь, так что +1! - person einpoklum; 16.07.2018
comment
У меня возникло бы искушение template<template<typename, typename...> class Ptr> явно указать количество ожидаемых параметров - person Caleth; 16.07.2018

Как предлагает @HolyBlackCat, нам больше не нужно использовать какие-либо обходные пути с C++ 17 - и код OP действительно компилируется (coliru.com).

GCC 6.3.0 по умолчанию компилирует код C++14 и не применяет это изменение семантики языка.

person einpoklum    schedule 16.07.2018