Reputation: 1155
I'd like to implement something like same_type() function in C++11 like below (this is what I have tried so far but it can not cope with the use cases mentioned below). The function is to check if T
is of the same type of the n-th argument of Args
, currently n=0 should be enough for my requirement, although n=other meaningful value would be something better to have (not very important if not straightforward).
template<typename T, typename... Args>
struct MyClass
{
// check if T is of the same type of the n-th argument of Args
bool same_type() {
// currently, I only check the first argument
// but if possible, it would be more useful to extend
// this function to check the n-th argument
return std::is_same<T,typename std::tuple_element<0, std::tuple<Args...> >::type>;
}
};
I have already had a look at this answer, but it does not consider the following use cases.
Use cases:
1.use with references and const
qualifier:
MyClass<int,const int&> c;
// expect to see 1, type of int should match const int&, i.e. reference or const should NOT affect the result
std::cout<<c.same_type();
2.use with no argument supplied:
MyClass<int> c;
// expect to see 0 as there is no variadic argument provided to compare with int
std::cout<<c.same_type();
Upvotes: 0
Views: 359
Reputation: 69854
I think you're looking to check compatibility more than 'sameness'. here's one way:
#include <tuple>
#include <type_traits>
#include <iostream>
#include <string>
template<class...Ts>
struct nth_is_compatible
{
using tuple = std::tuple<Ts...>;
template<class T, std::size_t N> static constexpr bool check()
{
return std::is_convertible<decltype(std::get<N>(std::declval<tuple>())), T>::value;
}
};
struct Monkey
{
Monkey(std::string) {} // conversion constructor
};
int main()
{
using checklist = nth_is_compatible<const int&, float, std::string>;
constexpr auto list = checklist();
std::cout << list.check<int, 0>() << std::endl;
std::cout << list.check<int, 1>() << std::endl;
std::cout << list.check<int, 2>() << std::endl;
// prove it's a constexpr and that it works for conversions
constexpr auto monkeyable = checklist::check<Monkey, 2>();
std::cout << monkeyable << std::endl;
}
Upvotes: 1
Reputation: 66200
I propose to develop a type traits isSameNth
as follows
template <std::size_t, typename...>
struct isSameNth;
template <std::size_t N, typename T, typename A0, typename ... As>
struct isSameNth<N, T, A0, As...> : public isSameNth<N-1U, T, As...>
{ };
template <std::size_t N, typename T>
struct isSameNth<N, T> : public std::false_type
{ };
template <typename T, typename A0, typename ... As>
struct isSameNth<0U, T, A0, As...> : public std::is_same<
typename std::remove_reference<T>::type const,
typename std::remove_reference<A0>::type const>
{ };
to transform same_type()
in a template static method (where the template value is N
)
template <typename T, typename... Args>
struct MyClass
{
template <std::size_t N>
static constexpr bool same_type()
{ return isSameNth<N, T, Args...>::value; }
};
The following is a full example (C++11 compliant)
#include <type_traits>
template <std::size_t, typename...>
struct isSameNth;
template <std::size_t N, typename T, typename A0, typename ... As>
struct isSameNth<N, T, A0, As...> : public isSameNth<N-1U, T, As...>
{ };
template <std::size_t N, typename T>
struct isSameNth<N, T> : public std::false_type
{ };
template <typename T, typename A0, typename ... As>
struct isSameNth<0U, T, A0, As...> : public std::is_same<
typename std::remove_reference<T>::type const,
typename std::remove_reference<A0>::type const>
{ };
template <typename T, typename... Args>
struct MyClass
{
template <std::size_t N>
static constexpr bool same_type()
{ return isSameNth<N, T, Args...>::value; }
};
int main ()
{
static_assert(
false == MyClass<int, long, int, short>::template same_type<0U>(), "!");
static_assert(
true == MyClass<int, long, int, short>::template same_type<1U>(), "!");
static_assert(
false == MyClass<int, long, int, short>::template same_type<2U>(), "!");
static_assert(
true == MyClass<int const, int &>::template same_type<0U>(), "!");
static_assert(
false == MyClass<int const &>::template same_type<0U>(), "!");
}
Upvotes: 1