2016-05-15 47 views
3

我是新来的可变参数模板和学习的缘故考虑下面的函数如何检查传递的参数类型可变参数函数

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...的类型来推导出阵列指针的类型,我的意思是没有使用<typename T>? ...我用decltype(ARG),但它没有工作...

注:请编辑标题问题,如果它是不恰当的...感谢

+0

不确定,但你尝试'typeid'函数。 – seleciii44

+0

您希望'args'与其他类型*相同,并且可能与'T'有所不同?或者你希望它们都与'T'类型相同?或者你允许它们彼此不同,但只是要求可以用可以转换为'T'的类型来构建'T'数组? –

回答

3

我发现的唯一方法是使使用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...); 

,编译器会再抛出一个错误,如果类型不SA我。


对于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来检测p arameters类型是相同的:

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

这是行得通的,但我不明白你的答案的最后一部分是元组部分......如果你可以简单地简化它,我将不胜感激...... +1无论如何 – Laith

+1

@Leo'std :: tuple'是一个标准可变参数模板,如'std :: pair',但是具有任意类型列表。还有'std :: tuple_element'辅助模板,它可以用于访问元组字段或通过索引访问元组字段的类型。在我们的例子中,'std :: tuple '表示模板类型的列表,并且我们使用'std :: tuple_element <...> :: type'在索引0处获取类型。至于模板参数有相同的类型,我们可以使用任何类型来为保存数组创建指针。 – user2807083

2

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

几点意见:

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

这很有帮助谢谢 – Laith

相关问题