为什么以下不起作用:
std::string fn(int i)
{
sleep(i); // number of seconds to sleep for
std::cout << "Exiting after pausing " << i << " seconds\n";
return std::to_string(i+1);
}
template<typename T, typename U>
int simult( std::function<T(U)> f, std::vector<U> args)
{
return 666;
}
int main()
{
std::vector<int> args { 6, 5, 7 };
int r = simult(fn, args);
}
函数simult显然不完整:我只想在这个阶段尝试编译。这个想法是你提供了一个函数和一个args列表,而simult将使用线程调用将args分段应用于f。
在这个阶段,我只想弄清楚编译问题。
simult.cc: In function ‘int main()’:
simult.cc:43:25: error: no matching function for call to ‘simult(std::__cxx11::string (&)(int), std::vector<int>&)’
int r = simult(fn, args);
^
simult.cc:23:5: note: candidate: template<class T, class U> int simult(std::function<T(U)>, std::vector<U>)
int simult( std::function<T(U)> f, std::vector<U> args)
^~~~~~
simult.cc:23:5: note: template argument deduction/substitution failed:
simult.cc:43:25: note: mismatched types ‘std::function<T(U)>’ and ‘std::__cxx11::string (*)(int) {aka std::__cxx11::basic_string<char> (*)(int)}’
int r = simult(fn, args);
^
答案 0 :(得分:1)
模板扣减不会触发隐式转换。虽然函数(指针)类型可转换到std::function
,但此转换从不是模板替换的一部分。
您必须构建std::function
并将其传递给simlut
:
int r = simult(std::function<std::string (int)>(fn), args);
答案 1 :(得分:1)
由于在模板参数推断中不考虑用户定义的转换,因此无法正常工作。
您可以通过显式提供模板参数来帮助编译器,并将simult
称为:
int r = simult<std::string, int>(fn, args);
或者您可以使用decltype
按照以下方式解决问题:
std::string fn(int i) {
return std::to_string(i + 1);
}
template<typename T, typename U>
int simult_impl(std::function<T(U)> f, std::vector<U> const &args) {
return 666;
}
template<typename F, typename U>
int simult(F f, std::vector<U> const &args) {
return simult_impl<decltype(f(args[0])), U>(f, args);
}
编辑:
如果要返回std::vector<T>
,只要您的编译器支持C ++ 14,您可以更改如下:
template<typename T, typename U>
std::vector<T> simult_impl(std::function<T(U)> f, std::vector<U> const &args) {
return std::vector<T>(10, T{"666"});
}
template<typename F, typename U>
auto simult(F f, std::vector<U> const &args) {
return simult_impl<decltype(f(args[0])), U>(f, args);
}
答案 2 :(得分:1)
使用@SergeyA的建议,我能够提出工作代码,现在作为一个完整的例子:
#include <functional>
#include <iostream>
#include <string>
#include <future>
#include <thread>
#include <vector>
#include <unistd.h> // for sleep. Not needed generally
// declare a function that does what you want
std::string fn(int i)
{
sleep(i); // number of seconds to sleep for
std::cout << "Exiting after pausing " << i << " seconds\n";
return std::to_string(i+1);
}
template<typename T, typename U>
std::vector<T> simult(std::function<T(U)> func, std::vector<U> const &args)
{
std::vector<std::future<T>> fs;
for(auto& a:args) fs.push_back(std::async(func, a));
std::vector<T> results;
for(auto &f:fs) results.push_back(f.get());
return results;
}
int main()
{
std::vector<int> args { 6, 5, 7 };
std::vector<std::string> results = simult(std::function<std::string (int)>(fn), args);
std::cout << "Results are:\n";
for(auto&r:results) std::cout << r << "\n"; //results are returned in correct order
return 0;
}
编译:
g++ simult.cc -o simult -lpthread
执行命令
time -p simult
Exiting after pausing 5 seconds
Exiting after pausing 6 seconds
Exiting after pausing 7 seconds
Results are:
7
6
8
real 7.00
user 0.00
sys 0.00
我仍然有点疑惑为什么C ++不能自己推断出函数的类型,但我想重要的是它是有效的。看来调用者对我来说是不必要的冗长。
修改:在功能simult()
中,将std::string
的实例替换为T
。
修改:将std::vector<U> args
更改为std::vector<U> const &args