我如何使这个模板参数可变
How do I make this template argument variadic?
假设我有这样的模板声明:
template <class A, class B, class C = A (&)(B)>
我该如何使其具有可变数量的C
类型的对象?执行class C ...c = x
将不起作用,因为可变模板参数不能具有默认值。这就是我尝试过的:
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (&type)(B);
};
template <class F, class B, typename helper<F(B)>::type ... C>
void f(C ...c) { // error
}
但直到最后一部分,我都收到了错误消息。我认为我做得不对。我在这里做错了什么?
我认为您可以使用以下方法。首先,一些类型特征的机器。这允许您确定参数包中的类型是否是同构的(我想您希望所有函数都具有相同的签名(:
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
然后,还有一些类型特征来计算泛型函数的签名:
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
最后,这就是如何定义可变函数模板:
template <typename... F>
void foo(F&&... f)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
// ...
}
这里有一个简短的测试:
int fxn1(double) { }
int fxn2(double) { }
int fxn3(string) { }
int main()
{
foo(fxn1, fxn2); // OK
foo(fxn1, fxn2, fxn3); // ERROR! not homogeneous signatures
return 0;
}
最后,如果你需要一个灵感,告诉你一旦有了论证包该怎么办,你可以看看我写的一个小图书馆(这个答案中使用的机器是从哪个部分提取的(。调用参数包F... f
中所有函数的一种简单方法如下(归功于@MarkGlisse(:
initializer_list<int>{(f(forward<ArgType>(arg)), 0)...};
你可以很容易地将其封装在一个宏中(只需看看马克对我发布的链接的回答(。
这是一个完整的、可编译的程序:
#include <iostream>
#include <type_traits>
using namespace std;
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
template <typename F>
void foo(F&& f)
{
cout << f(42) << endl;
}
template <typename... F>
void foo(typename homogeneous_type<F...>::type f, F&&... fs)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
cout << f(42) << endl;
foo(fs...);
}
int fxn1(double i) { return i + 1; }
int fxn2(double i) { return i * 2; }
int fxn3(double i) { return i / 2; }
int fxn4(string s) { return 0; }
int main()
{
foo(fxn1, fxn2, fxn3); // OK
// foo(fxn1, fxn2, fxn4); // ERROR! not homogeneous signatures
return 0;
}
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (*type)(B);
};
template<class F, class B>
void f()
{
}
template <class F, class B, typename... C>
void f(typename helper<F(B)>::type x, C... c)
{
std::cout << x(B(10)) << 'n';
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int main()
{
f<int,int>(identity,half,square,cube);
}
这里有一个可以推断类型的修改版本:
template<class F, class B>
void f(F(*x)(B))
{
x(B());
}
template <class F, class B, typename... C>
void f(F(*x)(B), C... c)
{
f(x);
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int string_to_int(std::string) { return 42; }
int main()
{
f(identity,half,square,cube);
// f(identity,half,string_to_int);
}
相关文章:
- 有没有办法使这段代码更快?
- 将指向数组的指针作为函数参数传递,这本身就是另一个函数的返回值?
- 为什么传递值参数经常使编译器更容易进行代码优化
- 将模板类与引用非类型模板参数一起使用时出现链接器错误
- 语法错误,也想知道我是否可以使这段代码更有效率
- Template()的参数转发使构造函数参数变为常量
- 元组和可变参数模板,这是如何工作的
- 我想我明白这一点.但是有没有办法使这更简单
- 有人可以告诉我任何不同的方法来使这段代码更快
- 获取参数,使总和接近 10^5
- 当你有一个像 ::lower 这样的参数时,这在C++中是什么意思
- "return-by-reference"或"pass-by-reference"参数何时与constexpr兼容?
- 如何使这两个模板类协同工作?(C++中的属性)
- CRT参数验证使多线程调试程序崩溃
- 警告:指针和整型之间的比较,传递' read '的参数1使指针的整型没有强制转换
- 我如何使用类型特征使这种数组到指针的转换明确
- 使用参数调用,这将从单个参数解析
- (SQLite + Qt + CodeBlock)如何使这3个作品
- 如何使这段代码更快
- 如何使这段代码更好?(C++温度转换器)