Другой способ сделать это не так лаконично, как ваше решение, я допускаю :-), но тот, который также обнаруживает классы, производные от basic_string и указатели на строку, будет:
namespace string_traits
{
typedef char yes_type;
struct no_type
{
char padding[8];
};
no_type string_helper(...);
template <typename charT, typename traits, typename Alloc>
yes_type string_helper(std::basic_string<charT, traits, Alloc>);
template <typename T>
typename std::remove_pointer<T>::type MakeT();
template <typename T>
struct is_string : std::integral_constant<bool,sizeof(string_helper(MakeT<T>()))==sizeof(yes_type)> {};
template <> struct is_string<void> : std::false_type { };
}
class TestString : public std::basic_string<char> { };
class A { };
template <bool b>
void check()
{
cout << (b?"Is string":"Is not string") << endl;
}
int main()
{
using namespace string_traits;
//not strings
check<is_string<void>::value>();
check<is_string<int>::value>();
check<is_string<int(&)[2]>::value>();
check<is_string<string(&)[2]>::value>();
check<is_string<string**>::value>();
check<is_string<A>::value>();
//strings
check<is_string<string>::value>();
check<is_string<TestString>::value>();
check<is_string<TestString&>::value>();
check<is_string<TestString*>::value>();
check<is_string<std::wstring>::value>();
check<is_string<string*>::value>();
check<is_string<string&>::value>();
}