Using a static_assert to determine if a specific template parameter is a specific untyped class template

c++, c++11

Solution

There are three ways of solving your problem, one would be an implementation of `is_specialization_of`, the other involves making your function take a `std::basic_string<T1,T2,T3>` instead of `TString`, and the third has the same philosophy as the 2nd solution; make a template matchable only by `std::basic_string`.

`is_base_of` isn't sufficient in your example because of two reasons:

`is_base_of` is used to see if type `U` is derived from `T` (or if it's the same type), in your snippet there is no inheritance involved.

`std::basic_string` isn't a complete type and therefore can't be used with `is_base_of` at all (which you already pointed out).

solution #1

`is_specialization_of` would be used to check whether type `U` is a specialization of the incomplete type `T`. It's quite easy to implement it using a template-template class, as in the below example.

as noted by @SebastianRedl variadic templates are not available using VS2012, see the other solutions (which are not as generic but still sufficient to your needs).

#include <type_traits>
#include <iostream>
#include <string>

template<template<typename...> class T, typename U>
struct is_specialization_of              : std::false_type { };

template<template<typename...> class T, typename... Ts> 
struct is_specialization_of<T, T<Ts...>> : std::true_type  { };

int
main (int argc, char *argv[])
{
  std::cerr << is_specialization_of<std::basic_string, std::string >::value << std::endl;
  std::cerr << is_specialization_of<std::basic_string, std::wstring>::value << std::endl;
  std::cerr << is_specialization_of<std::basic_string, std::istream>::value << std::endl;
}

output

1
1
0

solution #2

template <typename T1, typename T2, typename T3>
void strings_only_please(std::basic_string<T1,T2,T3>) {
  // ...  
}

Sure, the above won't result in a nice `static_assert` error - but it is sufficient for your needs and does what you want; the function is only callable by types who specialize `std::basic_string`.

solution #3

template<typename T>
struct is_basic_string : std::false_type { };

template<typename T1, typename T2, typename T3>
struct is_basic_string<std::basic_string<T1,T2,T3>> : std::true_type { };

...

is_basic_string<std::string >::value // true
is_basic_string<std::istream>::value // false

Problem

I'd like to have a function that restricts the parameters to be only types that derive from a specific templated class. In this case, `basic_string` (from the STL-docs). For example, a `wstring` is declared: ``` typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstring; ``` The basic idea would be something like this: ``` template <class TString> void strings_only_please(TString message) { static_assert(is_base_of<basic_string, TString>::value, "Not a string type!"); } ``` Of course, that doesn't compile though as basic_string hasn't been specified ... it needs a real type. (While I could likely just hard code the few actual string types, I'm looking for a general solution to this pattern.) I'm using Visual Studio 2012 and would ideally like the code to be portable to other modern C++ compilers, like GCC.

Original source