I have a function that takes a template type to determine a return value. Is there any way to tell at compile time if the template type is some instantiation of a template class?
Ex.
class First { /* ... */ };
template <typename T>
class Second { /* ... */ };
using MyType = boost::variant<First, Second<int>, Second<float>>;
template <typename SecondType>
auto func() -> MyType {
static_assert(/* what goes here?? */, "func() expects Second type");
SecondType obj;
// ...
return obj;
}
MyType obj = func<Second<int>>();
I know it is possible to get around this by doing
template <typename T>
auto func() -> MyType {
static_assert(std::is_same<T, int>::value || std::is_same<T, float>::value,
"func template must be type int or float");
Second<T> obj;
// ...
return obj;
}
MyType obj = func<int>();
I'm just curious in general if there is a way to test if a type is an instantiation of a template class? Because if MyType
ends up having 6 Second
instantiations, I don't want to have to test for all possible types.
Here's an option:
#include <iostream>
#include <type_traits>
#include <string>
template <class, template <class> class>
struct is_instance : public std::false_type {};
template <class T, template <class> class U>
struct is_instance<U<T>, U> : public std::true_type {};
template <class>
class Second
{};
int main()
{
using A = Second<int>;
using B = Second<std::string>;
using C = float;
std::cout << is_instance<A, Second>{} << '\n'; // prints 1
std::cout << is_instance<B, Second>{} << '\n'; // prints 1
std::cout << is_instance<C, Second>{} << '\n'; // prints 0
}
It's basically specializing the is_instance
struct for types that are instantiations of a template.
Another option, picking up on Henri's comment:
#include <iostream>
#include <type_traits>
#include <string>
template <class, template <class, class...> class>
struct is_instance : public std::false_type {};
template <class...Ts, template <class, class...> class U>
struct is_instance<U<Ts...>, U> : public std::true_type {};
template <class>
class Second
{};
template <class, class, class>
class Third
{};
int main()
{
using A = Second<int>;
using B = Second<std::string>;
using C = float;
using D = Third<std::string, int, void>;
std::cout << is_instance<A, Second>{} << '\n'; // prints 1
std::cout << is_instance<B, Second>{} << '\n'; // prints 1
std::cout << is_instance<C, Second>{} << '\n'; // prints 0
std::cout << is_instance<D, Third>{} << '\n'; // prints 1
}
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