Когда вы создаете специализацию, вы можете рассматривать параметры шаблона специализации как «переменные» для специализации. Вы можете указать столько, сколько хотите, но они должны использоваться в угловых скобках, которые являются частью класса.
При создании полной специализации вы не предоставляете никаких параметров шаблона - пустых угловых скобок.
Другие ответы HolyBlackCat и Jarod42 верны, поскольку они избавляют от ошибки вашего компилятора и обеспечивают работающую реализацию для ваших расплывчатых спецификаций.
Однако оба они предлагают сделать больше чем удаление cv-квалификаторов из типа. Я не рекомендую делать это, так как это противоречит принципам работы типов в стандартной библиотеке, и это может удивить пользователей.
Поскольку вы действительно хотите этого, я бы предложил предоставить отдельную метафункция, которая использует базовую c единицу и дает понять, что она удаляет ссылку.
static_assert(std::is_null_pointer<std::nullptr_t>::value);
static_assert(std::is_null_pointer<std::nullptr_t const volatile>::value);
static_assert(not std::is_null_pointer<std::nullptr_t &>::value);
static_assert(std::is_unsigned<unsigned long>::value);
static_assert(std::is_unsigned<unsigned long const volatile>::value);
static_assert(not std::is_unsigned<unsigned long &>::value);
Плюс, std::string
- это только один из возможных стандартных типов строк. Как насчет строки, использующей другой тип символов (например, std::wstring
) или тот же тип символов, но другой распределитель (например, std::pmr::string
)?
Они уже показывают, как ограничить вашу черту только std::string
. Вот один из способов сделать это для любого стандартного строкового типа.
namespace detail {
template <typename T>
struct is_string
: std::false_type
{};
// Partial specialization - parameters used to qualify the specialization
template <typename CharT, typename TraitsT, typename AllocT>
struct is_string<std::basic_string<CharT, TraitsT, AllocT>>
: std::true_type
{};
}
template <typename T>
using is_basic_string = detail::is_string<std::remove_cv_t<T>>;
static_assert(is_basic_string<std::string>::value);
static_assert(is_basic_string<std::string const volatile>::value);
static_assert(not is_basic_string<std::string &>::value);
static_assert(is_basic_string<std::wstring>::value);
static_assert(is_basic_string<std::pmr::string>::value);