Using static_assert to determine if a particular template is a specific template of an untyped class

I would like to have a function that restricts parameters only to types that come from a specific template class. In this case, basic_string (from STL docs ). For example, wstring 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, this does not compile, but since basic_string is not specified ... it needs a real type. (Although I could just simply copy a few actual line types, I am looking for a general solution for this template.)

I am using Visual Studio 2012 and ideally would like this code to be portable for other modern C ++ compilers like GCC.

+4
source share
1 answer

There are three ways to solve your problem: one of them will be the implementation of is_specialization_of , the second is to force your function to accept std::basic_string<T1,T2,T3> instead of TString , and the third has the same philosophy as the second solution; make the template suitable only for std::basic_string .


is_base_of not enough in your example due to two reasons:

  • is_base_of used to find out if type U not derived from T (or if it is of the same type), there is no inheritance in your fragment.

  • std::basic_string not a full type and therefore cannot be used with is_base_of at all (as you already mentioned).


solution # 1

is_specialization_of will be used to check if type U specialization of an incomplete type T This is pretty easy to implement with a template, as in the example below.

as noted by @SebastianRedl variation patterns, are not available using VS2012, see other solutions (which are not common, but still sufficient for 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>) { // ... } 

Of course, the above will not lead to a nice static_assert error - but this is enough for your needs and does what you want; a function can only be called by types specializing in std::basic_string .


decision # 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 
+10
source

Source: https://habr.com/ru/post/1490739/


All Articles