C++11 Is_Same Type Trait for Templates

C++11 is_same type trait for templates

You have to write your own, but it's simple:

template<typename>
struct is_std_array : std::false_type {};

template<typename T, std::size_t N>
struct is_std_array<std::array<T,N>> : std::true_type {};

std::is_same equivalent for unspecialised template types

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";
}

How to use type_traits is_same for std::array

The problem is that container.size() is not a constant expression and can't be used as non-type template argument.

You can add a type trait to get the size at compile-time (or use std::tuple_size directly as @康桓瑋 commented). E.g.

template <typename>
struct get_array_size;
template <typename T, size_t S>
struct get_array_size<std::array<T, S>> {
constexpr static size_t size = S;
};

Then use it as:

if constexpr (std::is_same<T, std::array<uint8_t, get_array_size<T>::size>>::value)

Note that you have to move the if branch for std::string before the one before std::array. Otherwise you need to define size (and give it a default value) in the primary template too.

Using type traits in C++ template functions, is it possible to convert a value to a T of the same type?

So, is there a way to return different types from a template function
depending on the template parameter in C++?

Yes, you can use C++17 constexpr if

template<typename T>
T doSomething() {
//Code

if constexpr (std::is_same<T, int>::value) {
return getInt(); // A library function returning an int
} else if constexpr (std::is_same<T, bool>::value) {
return getBool(); // A library function returning a bool
} else {
throw;
}
}

C++ 11: How to write 2 template functions that differ in their return type

You can use the type trait std::is_enum, and apply SFINAE.

template<typename T>
typename std::enable_if<std::is_enum<T>::value, boost::optional<T>>::type
func(const std::string &s) {
return boost::make_optional(EnumMapper<T>::map_string_to_enum<T>(s));
}

Note that you have to constrain on type for the 1st overload too. You can check whether it's int, or use std::is_integral. E.g.

template<typename T>
typename std::enable_if<std::is_same<T, int>::value, boost::optional<T>>::type
func(const std::string &s) {
return boost::make_optional(std::stoi(s));
}

Implement a type trait for a class template that is true for the actual class template and classes that inherit it

C++20 concepts make things much easier:

template <class... Ts>
struct Foo {};

template<class T>
concept IsFoo = requires(T& t){
[]<class... Ts>(Foo<Ts...>&){}(t);
};

Demo.

Template class with conditional typenames

Typically you'd do this by creating a trait type whose specializations define the additional types. For example:

// Base template is undefined.
template <typename T>
struct optix_traits;

template <>
struct optix_traits<float> {
using dim2 = optix::float2;
// etc
};

template <>
struct optix_traits<double> {
using dim2 = optix::double2;
// etc
};

Then you can alias from these types to a name in your type, if desired:

template <typename T>
class MyClass {
public:
using T2 = typename optix_traits<T>::dim2;
};

Determing type of template parameter in c++

You are looking for std::is_same.

#include <string>
#include <type_traits>
#include <vector>

struct MyClass {
template <typename T>
void increment(std::string stats, T tags);
};

template <typename T>
void MyClass::increment(std::string stats, T tags)
{
if (std::is_same<T,std::string>::value)
{
//Perform some string manipulation
}
else if (std::is_same<T,std::vector<std::string>>::value)
{
//Extract each string from the vector
}
else
{
//only strings or vectors are supported
}
}

You definitely should prefer overloading but if you do not want to repeat the function declaration in the class body and also do not want to inline the function in the class, you could use explicit specialization with a deleted primary template. This will trigger a compiler error if the function is not implemented for this type.

#include <string>
#include <type_traits>
#include <vector>

struct MyClass {
template <typename T>
void increment(std::string stats, T tags) = delete;
};

template <>
void MyClass::increment(std::string stats, std::string tags)
{
//Perform some string manipulation
}

template <>
void MyClass::increment(std::string stats, std::vector<std::string> tags)
{
//Extract each string from the vector
}

int main() {
MyClass{}.increment(std::string{}, std::string{});
MyClass{}.increment(std::string{}, std::vector<std::string>{});
MyClass{}.increment(std::string{}, int{}); // BOOM!
}

How to switch passed value through C++ standard type trait?

You can use SFINAE to reject overloads

template<typename T>
typename std::enable_if<std::is_integral<T>::value || std::is_enum<T>::value>::type
func(T t)
{
return t;
}

template<typename T>
typename std::enable_if<std::is_floating_point<T>::value>::type
func(T t)
{
return t;
}

template<typename T>
typename std::enable_if<std::is_same<T, std::string>::value>::type
func(T t)
{
return t;
}

or use tag dispatching similar to what you've shown, but handle the alternatives differently to reduce the number of cases

namespace detail
{
template<typename T>
T func(T t, std::false_type /*is_string*/, std::false_type /*is_float*/, std::true_type /*is_int*/)
{
return t;
}

template<typename T>
T func(T t, std::false_type /*is_string*/, std::true_type /*is_float*/, std::false_type /*is_int*/)
{
return t;
}

template<typename T>
T func(T t, std::true_type /*is_string*/, std::false_type /*is_float*/, std::false_type /*is_int*/)
{
return t;
}
}

template<typename T>
T func(T t)
{
return detail::func(t, std::is_same<string, T>(),
std::is_floating_point<T>(),
std::integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value>());
}


Related Topics



Leave a reply



Submit