【问题标题】:How to check the type of passed arguments to variadic function如何检查传递参数的类型到variadic函数
【发布时间】:2016-09-11 04:36:04
【问题描述】:

我是可变参数模板的新手,为了学习考虑以下函数

template <typename T, typename... args>
T* make_arr(args... arg) {

   // Code to check if passed args are of the same type

   T* arr = new T[sizeof...(arg)]{ arg... };
   return arr;
}

我有两个问题:

  1. 我希望函数被模板化,并且我希望传递的参数是相同的类型,所以问题是:是否可以检查传递的参数是否是相同的类型?
  2. 是否可以通过推断args...的类型来推断数组指针的类型,我的意思是不使用&lt;typename T&gt;? ...我使用了 decltype(arg) 但它没有用...

注意:如果不合适,请编辑标题问题...谢谢

【问题讨论】:

  • 不确定,但您是否尝试过typeid 函数。
  • 您希望args 具有彼此 相同的类型,并且可能与T 不同?或者您希望它们都与T 的类型相同?或者您允许它们彼此不同,但只要求可以使用可以转换为 T 的类型构建您的 T 数组?

标签: c++ templates variadic


【解决方案1】:

我发现的唯一方法是使用 SFINAE 制作一个辅助函数

//Basic function
template<typename T>
void allsame(T) {}

//Recursive function
template<typename T, typename T2, typename... Ts, 
typename = std::enable_if_t<std::is_same<T, T2>::value>>
void allsame(T arg, T2 arg2, Ts... args)
{
    allsame(arg2, args...);
}

然后你可以这样称呼它:

allsame(arg...);

如果类型不同,编译器会抛出错误。


对于 2),您可以修改 allsame 以返回类型。此函数的唯一缺点是,如果类型不是默认可构造的,它将无法工作。

template<typename T>
T allsame(T) { return{}; }

T allsame(T arg, T2 arg2, Ts... args)

然后,你可以decltype(allsame(args...))获取类型

【讨论】:

    【解决方案2】:

    首先,您需要以下内容:

    #include <type_traits>
    #include <tuple>
    

    然后,让我们声明可变参数模板来检测类型是否相同:

    template <typename ... args>
    struct all_same : public std::false_type {};
    
    
    template <typename T>
    struct all_same<T> : public std::true_type {};
    
    
    template <typename T, typename ... args>
    struct all_same<T, T, args...> : public all_same<T, args ... > {};
    

    现在我们可以使用static_assert 来检测参数类型是否相同:

    template <typename T, typename... args>
    T* make_arr(args... arg) {
    
       // Code to check if passed args are of the same type
       static_assert(all_same<args ...>::value, "Params must have same types");
    
       T* arr = new T[sizeof...(arg)]{ arg... };
       return arr;
    };
    

    最后,让我们将函数的返回类型作为第一个参数类型 - 如果所有类型都相同,我们可以采用其中任何一个。我们为此使用std::tuple

    template <typename... args>
    typename std::tuple_element<0, std::tuple<args...> >::type * make_arr(args... arg) {
    
       // Code to check if passed args are of the same type
       static_assert(all_same<args ...>::value, "Params must have same types");
    
       typedef typename std::tuple_element<0, std::tuple<args...> >::type T;
    
       T* arr = new T[sizeof...(arg)]{ arg... };
       return arr;
    };
    

    【讨论】:

    • 这确实有效,但我不明白你答案的最后一部分是元组部分......如果你能简单地简化它,我将不胜感激......无论如何+1
    • @Leo std::tuple 是一个标准的可变参数模板,类似于std::pair,但具有任意类型列表。还有std::tuple_element 帮助模板,可用于访问元组字段或通过其索引来键入元组字段。在我们的例子中,std::tuple&lt;args.. &gt; 表示模板类型列表,我们使用std::tuple_element&lt;...&gt;::type 在索引 0 处获取类型。到目前为止,模板参数具有相同的类型,我们可以将其用作类型来制作用于保存数组的指针。
    【解决方案3】:

    constexpr bool 函数开始检查所有布尔值是否为真。这在检查所有 is_same 调用是否都是 true 时很有用。

    constexpr bool all() {
        return true;
    }
    template<typename ...B>
    constexpr bool all(bool b, B... bs) {
        return b && all(bs...);
    }
    

    不管怎样,这里是make_arr函数:

    template <typename... args
    , class ...
    , typename T = std::tuple_element_t<0, std::tuple<args...>>
    , typename = std::enable_if_t< all(std::is_same<T, args>{}...) >
    >
    T* make_arr(args&&... arg) {
        static_assert( all(std::is_same<T, args>{}...) ,"");
        T* arr = new T[sizeof...(arg)]{ std::forward<args>(arg)... };
        return arr;
    }
    

    几个cmets:

    • 使用完美转发,&amp;&amp;std::forward,以避免在您的类型很大时出现潜在的副本。
    • 提取第一个参数的类型by creating a std::tuple type and using std::tuple_element&lt;0, ..&gt;
    • 使用static_assert,将每种类型与第一种类型进行比较(通过is_same)。
    • 我猜你希望 SFINAE '隐藏'这个函数,除非类型都是相同的。这是通过typename = std::enable_if_t&lt; ..boolean-expression.. &gt; 实现的
    • class ... 本质上是多余的。它的唯一目的是使开发人员无法通过手动指定类型(make_arr&lt;int,char,size_t,bool&gt;(..))来欺骗检查。但是,也许这太保守了——static_assert 无论如何都会抓住他们!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-18
      • 2023-03-30
      • 2012-02-08
      • 2015-10-24
      • 1970-01-01
      • 1970-01-01
      • 2016-12-04
      • 2020-05-13
      相关资源
      最近更新 更多