检查第 n 个可变参数模板参数是否属于特定类型

check if the n-th variadic template argument is of a certain type

本文关键字:参数 属于 是否 类型 变参 检查      更新时间:2023-10-16

我想在 C++11 中实现类似 same_type(( 函数的东西,如下所示(这是我到目前为止尝试过的,但它无法应对下面提到的用例(。该函数是检查T是否与 Args 的第 n 个参数的类型相同,目前 n=0 应该足以满足我的要求,尽管 n=其他有意义的值会更好(如果不是很简单,不是很重要(。

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

我已经看过这个答案,但它没有考虑以下用例。

使用案例:

1.与引用和const限定符一起使用:

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.使用时不带参数:

MyClass<int> c;
// expect to see 0 as there is no variadic argument provided to compare with int
std::cout<<c.same_type();    

我建议开发一个类型特征isSameNth如下

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

在模板静态方法中转换same_type()(其中模板值为 N (

template <typename T, typename... Args>
struct MyClass
 {
   template <std::size_t N>
   static constexpr bool same_type()
    { return isSameNth<N, T, Args...>::value; }
 };

以下是完整示例(符合 C++11(

#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>(), "!");
 }

我认为您更希望检查兼容性而不是"相同性"。 这是一种方法:

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