When you create a specialization, you can kinda think of the template parameters of the specialization as "variables" for the specialization. You can give as many as you want, but they must be used in the angle brackets that are part of the class.
When you create a full specialization, you do not provide any template parameters - empty angle brackets.
The other answers by HolyBlackCat and Jarod42 are correct, in that they get rid of your compiler error, and provide a working implementation for your vague specifications.
However, both of them suggest doing more than removing cv-qualifiers from the type. I do not recommend doing this, as it goes against how the type traits in the standard library work and it could be quite surprising to users.
Since you actually want that as a result, I would suggest providing a separate metafunction that uses the basic one, and make it clear that it is removing the reference.
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);
Plus, std::string is just one of the possible standard string types. What about a string using a different character type (e.g., std::wstring), or the same character type but a different allocator (e.g., std::pmr::string)?
Those already show how to limit your trait for just std::string. Here is one way to do it for any standard string type.
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);