如何检查传递给可变参数函数的参数类型
How to check the type of passed arguments to variadic function
我是可变参数模板的新手,为了学习考虑以下函数
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) 但它没有用...
注意:如果标题问题不合适请修改...谢谢
我找到的唯一方法是使用 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
修改为 return。此函数的唯一缺点是如果类型不是默认可构造的,它将无法工作。
template<typename T>
T allsame(T) { return{}; }
T allsame(T arg, T2 arg2, Ts... args)
然后,您可以decltype(allsame(args...))
获取类型
首先,您需要这些包括:
#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;
};
最后,让我们将函数的 return 类型作为第一类参数 - 如果所有类型都相同,我们可以采用其中任何一个。我们为此使用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;
};
从 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, ..>
。
使用 - a
static_assert
,其中每种类型与第一种类型进行比较(通过 is_same
)。
- 我猜你想让 SFINAE 'hide' 这个函数,除非类型都相同。这是通过
typename = std::enable_if_t< ..boolean-expression.. >
实现的
-
class ...
本质上是多余的。它的唯一目的是使开发人员无法通过手动指定类型(make_arr<int,char,size_t,bool>(..)
)来欺骗检查。然而,也许这太保守了——static_assert
无论如何都会抓住他们!
我是可变参数模板的新手,为了学习考虑以下函数
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) 但它没有用...
注意:如果标题问题不合适请修改...谢谢
我找到的唯一方法是使用 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
修改为 return。此函数的唯一缺点是如果类型不是默认可构造的,它将无法工作。
template<typename T>
T allsame(T) { return{}; }
T allsame(T arg, T2 arg2, Ts... args)
然后,您可以decltype(allsame(args...))
获取类型
首先,您需要这些包括:
#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;
};
最后,让我们将函数的 return 类型作为第一类参数 - 如果所有类型都相同,我们可以采用其中任何一个。我们为此使用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;
};
从 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 usingstd::tuple_element<0, ..>
。
使用 - a
static_assert
,其中每种类型与第一种类型进行比较(通过is_same
)。 - 我猜你想让 SFINAE 'hide' 这个函数,除非类型都相同。这是通过
typename = std::enable_if_t< ..boolean-expression.. >
实现的
-
class ...
本质上是多余的。它的唯一目的是使开发人员无法通过手动指定类型(make_arr<int,char,size_t,bool>(..)
)来欺骗检查。然而,也许这太保守了——static_assert
无论如何都会抓住他们!