我是可变参数模板的新手,为了学习,请考虑以下函数
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;
}
我有两个问题:
args...
的类型推断出数组指针的类型,我的意思是不使用<typename T>
? ...我使用了decltype(arg),但它没有用...... 注意:如果不合适,请编辑标题问题...谢谢
答案 0 :(得分:4)
我发现的唯一方法是使用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...))
获取类型
答案 1 :(得分: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;
};
答案 2 :(得分: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
,以避免在类型较大时发布潜在副本。std::tuple
type and using std::tuple_element<0, ..>
。static_assert
,其中每种类型与第一种类型进行比较(通过is_same
)。typename = std::enable_if_t< ..boolean-expression.. >
class ...
基本上是多余的。它的唯一目的是让开发人员无法通过手动指定类型(make_arr<int,char,size_t,bool>(..)
)来欺骗检查。但是,也许这太保守了 - static_assert
无论如何都会抓住它们!