我正在研究一些速记函数式编程方法,以帮助用C ++进行数据分析,我遇到了一种情况,我觉得我的实施工作应该有效,但g ++不同意我的看法。请参阅以下代码:
#include <algorithm>
#include <valarray>
#include <functional>
#include <iostream>
using namespace std;
//generates a list of [from,to] in increments of step. last is <= to with precision of step
template<typename T> std::valarray<T> range(T from, T to, T step = 1) {
size_t elems = (size_t)floor((to-from)/step) + 1;
std::valarray<T> result(elems);
for (int i = 0; i < elems; i++) {
result[i] = from+step*i;
}
return result;
}
//map over multiple lists as arguments to the provided function
template<typename T, typename... Ts> void mapthreadv(std::function<void(T,Ts...)> func, std::valarray<T> &in, std::valarray<Ts>&... rest) {
for (int i = 0; i < in.size(); i++) {
func(in[i],rest[i]...);
}
}
int main(int argc, char **argv) {
auto first = range(0.0,1.0,0.1);
auto second = range(0.0,10.0,1.0);
auto third = range(0.0,100.0,10.0);
mapthreadv<double,double,double>([](double a, double b, double c) { cout << '{' << a << ',' << b << ',' << c << "},"; },first,second,third);
}
预期输出为:
{0,0,0},{0.1,1,10},{0.2,2,20},{0.3,3,30},{0.4,4,40},{0.5,5,50},{0.6,6,60},{0.7,7,70},{0.8,8,80},{0.9,9,90},{1,10,100},
可以通过直接指定<void(double,double,double)>
代替<void(T,Ts...)>
到std::function
来实现,但这显然不是一个有用的修复方法。代码无法按编写方式编译,错误与模板参数推断/替换有关:
‘main(int, char**)::<lambda(double, double, double)>’ is not derived from ‘std::function<void(double, Ts ...)>’
所以我的直觉是,由于某种原因,Ts没有被扩展......我的任何指针或明显的疏忽?我对模板功能一般都很陌生,所以感谢任何帮助。
答案 0 :(得分:2)
问题是当您使用模板参数包时仍然会执行模板参数推导,即使您明确指定了类型(第14.8.1节[temp.arg.explicit] / p9):
模板参数推导可以扩展模板的顺序 对应于模板参数包的参数,即使是 sequence包含显式指定的模板参数。 [ 实施例:
template<class ... Types> void f(Types ... values); void g() { f<int*, float*>(0, 0, 0); } // Types is deduced to the sequence int*, float*, int
- 结束示例]
并且,由于lambda闭包类型不是std::function
,模板参数推断将失败。
无论如何都没有理由在这里使用std::function
;您可以简单地将仿函数作为模板参数:
template<typename F, typename T, typename... Ts> void mapthreadv(F func, std::valarray<T> &in, std::valarray<Ts>&... rest) {
for (int i = 0; i < in.size(); i++) {
func(in[i],rest[i]...);
}
}
也避免了明确指定模板参数的需要:
mapthreadv([](double a, double b, double c) { std::cout << '{' << a << ',' << b << ',' << c << "},"; },first,second,third);