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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With