2016-06-09 74 views
6

为什么没有了以下工作:调试模板推演失败

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是不完整的:我只是想获得的东西在这个阶段进行编译。这个想法是你提供了一个函数和一个参数列表,而simult会使用线程调用将这个参数分段地应用到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

你没有真正给编译器的帮助!首先传入一个函数指针,然后它必须分配给一个'std :: function <>'来确定模板类型? – Nim

+0

Ha。我总是使用666作为测试整数。基于这些理由,我喜欢这个,再加上一个。 – Bathsheba

+0

@Bathsheba居然在80%的神圣文本中的数字是616而不是666,所以你没有什么可担心的... – 101010

回答

1

模板扣除不会触发隐式转换。尽管函数(指针)类型是可转换std::function,但此转换不是模板替换的一部分。

您必须构建std::function并把它传递给simlut

int r = simult(std::function<std::string (int)>(fn), args); 
+0

downvote的原因是...? – SergeyA

1

它不工作,由于这样的事实:用户定义的转换不会在模板参数推导考虑。

你既可以帮助编译器通过显式提供模板参数,并调用simult为:

int r = simult<std::string, int>(fn, args); 

Live Demo

或者你可以让它工作了与使用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); 
} 

Live Demo

编辑:

如果你想返回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); 
} 

Live Demo

+0

我特别喜欢你的第二部分,但最终我不想返回'int',我想返回'std :: vector ',这取决于如何定义传递的函数。 – blippy

+0

@blippy查看编辑 – 101010

+0

非常感谢。我会看看。是的,我有一个C++ 14编译器。 – blippy

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; 
} 

Compil E:

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> argsstd::vector<U> const &args