Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Templates 将可变模板转换为函数调用的线性编译时算法_Templates_C++11_Variadic Templates - Fatal编程技术网

Templates 将可变模板转换为函数调用的线性编译时算法

Templates 将可变模板转换为函数调用的线性编译时算法,templates,c++11,variadic-templates,Templates,C++11,Variadic Templates,我有一个可变模板函数,它接受任意数量的参数。我需要将这些参数转换为顺序重要的函数调用序列。以下方法有效: #include <iostream> #include <typeinfo> #include <vector> void printType(const std::type_info& ti) { printf("%s\n", ti.name()); } void expandVariadic() { } template<

我有一个可变模板函数,它接受任意数量的参数。我需要将这些参数转换为顺序重要的函数调用序列。以下方法有效:

#include <iostream>
#include <typeinfo>
#include <vector>

void printType(const std::type_info& ti) {
    printf("%s\n", ti.name());
}

void expandVariadic() {
}

template<typename First, typename... Rest>
void expandVariadic(const First& first, const Rest&... rest) {
    printType(typeid(First));
    expandVariadic(rest...);
}

int main(int argc, const char* argv[]) {
    expandVariadic(10, "hi", std::cout, std::vector<int>());
    return 0;
}
#包括
#包括
#包括
无效打印类型(const std::type_info&ti){
printf(“%s\n”,ti.name());
}
空变量(){
}
模板
可变变量(常数优先和第一,常数静止和…静止){
打印类型(typeid(第一个));
可扩展变量(rest…);
}
int main(int argc,const char*argv[]{
可扩展变量(10,“hi”,std::cout,std::vector());
返回0;
}
但是,上面的代码扩展为传递给ExpandVariatic的二次参数数。我可以强制内联扩展变量,但这仍然意味着二次编译时间

是否有一种线性时间方法来实现上述功能


(它们需要是函数调用:想象一个记录器生成一系列输出调用,或者用类型信息填充向量。)

在调用任何函数时,存在一个常见的技巧,即在不递归的情况下扩展参数包:

#包括
#包括
#包括
无效打印类型(const std::type_info&ti){
std::cout
struct sink{templatesink(T&&){};};
按顺序()运行{}
模板
按顺序无效运行(Fs&…Fs){
sink[]={((void)std::forward(fs)(),0);
接收器{{};//警告消除
}
使用:

模板
可变变量(常数Ts和…Ts){
按顺序运行([&]{printType(typeid(ts));};
}
它很好地隐藏了
run\u in_order
run\u in_order
中的魔力,它获取一系列lambda或其他空可调用对象,并按从左到右的顺序调用它们。这是因为
接收器的
{}
中的求值
行由C++11标准保证从左到右

我将返回值强制转换为
void
,然后在RHS上使用
0
调用逗号运算符,以确保我们得到一个可以转换为
接收器的值。
(void)
强制转换处理一种情况,即传入的lambda返回一个覆盖
运算符的对象,


这种技术的缺点是,对lambda内部包的支持不如对其他包扩展的支持广泛。我提到的许多编译器都能够对大多数代码进行参数包扩展,但当所讨论的参数包在lambda内部,而扩展在lambda外部时,就失败了。

o向
数组中添加一个额外的元素,而不是重载?
接收器([]={0,((void)forward(fs)),0)};
tyepname fs
应该是
typename…fs
,而
接收器(
应该是
接收器{}
以防止它被解析为
\uu
作为类型
sink
的新声明,并在
{…}中从左到右计算初始化器如果我没记错的话,
至少在GCC中还没有实现。@hvd没有意识到那个GCC错误。我的下一个尝试是分割和控制参数,这会使n lg n编译复杂度而不是n^2。
按顺序运行的一个好处是至少这些细节隐藏在它里面,而不是在每个使用站点。哦我应该将
(void)blah,0
替换为
sink{blah}
进行一点实验:可以避免lambda,它表明在这个特定的情况下,GCC确实使用了正确的求值顺序。我看不出上面的代码如何导致“传递的参数的平方数”,可以简单解释一下吗?
#include <iostream>
#include <typeinfo>
#include <vector>

void printType( const std::type_info& ti ) {
    std::cout << ti.name() << '\n';
}

// because cast to void is a non generic way to hide unused variable warning.
template <typename T> void ignore(T&&) {}

template<typename... Ts>
void expandVariadic(Ts&&... ts) {
    // expand by using a initializer list.
    auto il { ( printType( typeid(std::forward<Ts>(ts)) ), 0)... };
    ignore(il);
}

int main(int argc, const char* argv[]) {
    expandVariadic(10, "hi", std::cout, std::vector<int>());
    return 0;
}
struct sink{template<class T>sink(T&&){};};
void run_in_order(){}
template<typename... Fs>
void run_in_order(Fs&&...fs){
  sink _[]={((void)std::forward<Fs>(fs)(),0)...};
  sink{_};// warning elimination
}
template<typename... Ts>
void expandVariadic(const Ts&... ts) {
  run_in_order([&]{printType(typeid(ts));}...);
}