Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if two types come from the same templated class [duplicate]

I would like to check if two types are the same, but regardless of their template parameters. Something like this:

template<class T>
class A {};
class B {};

int main() {
    cout << std::is_same_template<A<int>, A<string>>::value << endl; // true
    cout << std::is_same_template<A<int>, B>::value << endl; // false
}

I am aware of std::is_same for checking if two types match exacty.

A reason why I need this: I have a templated method that can be called with any type, but I would like to prohibit that is is called with type A (which is templated), possibly by using a static_assert. Were A not templated, I believe it could be done easily using std::is_same, but now, I have a problem...

EDIT: I can manually exclude A for a few common Ts, using, I am looking for a way to do it for all T:

static_assert(!std::is_same<parameter_type, A<int>>::value, "Cannot use this function with type A<T>");
static_assert(!std::is_same<parameter_type, A<double>>::value, "Cannot use this function with type A<T>");
static_assert(!std::is_same<parameter_type, A<bool>>::value, "Cannot use this function with type A<T>");
like image 722
jureslak Avatar asked Oct 24 '15 21:10

jureslak


2 Answers

I've come up with a simpler way than @NikitaKakuev's answer, currently used on a project of mine.

template<typename, typename>
constexpr bool is_same_template{false};

template<
    template<typename...> class T, //typename T in C++17
    typename... A,
    typename... B
>
constexpr bool is_same_template<
    T<A...>,
    T<B...>
>{true};

The only current issue is with templates that mix types and typenames, ie. std::array<int, 10>.
To overcome this limitation, specialization is required.

Usage:

bool b = is_same_template<std::string, std::wstring>;  //true
//both are typedefs of std::basic_string

EDIT: As requested by @Helix in the comment below, specialization for std::array (or any other template with the same signature):

template<
    template<typename, std::size_t> class T, //typename T in C++17
    typename TA, std::size_t NA,
    typename TB, std::size_t NB
>
constexpr bool is_same_template<
    T<TA, NA>,
    T<TB, NB>
>{true};
like image 98
bit2shift Avatar answered Sep 30 '22 01:09

bit2shift


Okay, how about this:

#include <iostream>

template<class T>
struct A {};
struct B {};

template <typename T>
struct should_reject { static constexpr bool value = false; };

template <typename T>
struct should_reject<A<T>> { static constexpr bool value = true; };

template <typename T>
void rejectA(T t)
{
    std::cout << should_reject<T>::value << std::endl;
}

int main() {
    rejectA(B());         // false
    rejectA(1);           // false
    rejectA(1.0);         // false
    rejectA(A<B>());      // true
    rejectA(A<int>());    // true
    rejectA(A<double>()); // true
}
like image 27
Nikita Kakuev Avatar answered Sep 30 '22 01:09

Nikita Kakuev