Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::is_same equivalent for unspecialised template types

In one project I have found a possibility to stay DRY as a lot of code except for some small parts could stay the same for template specialisations of a template. Here is a small working example what I'm currently doing to check which templated class I'm using:

template<typename T>
class A{};

template<typename T>
class B{};

template<template<class> class C>
void do_stuff()
{
    if(std::is_same<A<int>,C<int>>::value)
    {
    // Do Stuff for A
    } else if(std::is_same<B<int>,C<int>>::value)
    // Do Stuff for B
    }
}

int main()
{
    do_stuff<A>();
}

What I would like to do instead is using

std::is_same<A,C>::value

to determine the template type. Is there any function that could help me or am I missing a pattern that would work better in this case?

I see that I could do something like

template<template<class> class C, typename T>
void do_stuff();

do_stuff<A,T>();

but that seems like the wrong way to do for me.

like image 572
kreisrund Avatar asked Jul 28 '16 08:07

kreisrund


People also ask

Which keyword is equivalent to typename in C++ template?

For naming template parameters, typename and class are equivalent.

How std:: is_ same works?

The std::is_same template of C++ STL is used to check whether the type A is same type as of B or not. It return the boolean value true if both are same, otherwise return false.

What is the difference between template typename T and template T?

There is no difference. typename and class are interchangeable in the declaration of a type template parameter.

Which of the data types are supported by template?

All data types, both primitive and compound types, must be defined by using a template.


1 Answers

You could write an is_same_template trait which is partially specialized for when the two template template parameters are the same:

template <template <typename...> class, template<typename...> class> 
struct is_same_template : std::false_type{};

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

Then you can write is_same_template<A,C>::value.

Note that this won't work for templates which have non-type template parameters, like std::array.

Some compilers will not consider an alias template to be equivalent to the template it aliases, so the following would result in std::false_type:

template <typename T, typename Alloc>
using MyVec = std::vector<T, Alloc>;

is_same_template<std::vector, MyVec>;

This is considered a defect in the standard, but you shouldn't rely on behaviour until this fix is implemented in all common compilers.


That said, you need to be careful about what you put in those if branches, as the code needs to compile regardless of what the template is instantiated with. In C++17 you'll be able to use if constexpr to solve this problem, but for now you'll need to tag dispatch or have different specializations if the branches have code which is only valid for A or B.

template <template <typename...> class> struct tag{};

template <template <typename> class T>
void do_stuff() {
    do_stuff(tag<T>{});
}

void do_stuff(tag<A>) {
    std::cout << "A";
}

void do_stuff(tag<B>) {
    std::cout << "B";   
}
like image 165
TartanLlama Avatar answered Nov 07 '22 08:11

TartanLlama