我对C ++很陌生,我正在体验它的一些功能。特别是,我想实现一个通用的 Divide and Conquer 过程,该过程将“功能代码”作为参数来解决问题。实际上我的想法是“分而治之”是一个更高阶的函数作为参数:
basecase()
来测试我们是否达到了基本情况solvecase()
divide()
,用于将问题分解为两个子问题conquer()
,它采用部分解决方案并从两个解决方案中构建一个解决方案。为此,我使用了模板:特别是类型A
是输入问题的类型,类型B
是输出问题的类型和类型C
可能是一个布尔值(基本情况的测试的结果类型)。
还有其他一些东西,例如使用async()
同时计算解决方案,但这不是我问题的重点。
我的问题是:为什么我在编译时收到以下消息,抱怨冲突类型?
D&C.cpp: In function ‘int main(int, char**)’:
D&C.cpp:67:92: error: no matching function for call to ‘divideAndConquer(std::string&, main(int, char**)::__lambda4&, main(int, char**)::__lambda5&, main(int, char**)::__lambda6&, main(int, char**)::__lambda7&)’
divideAndConquer(text, lambda_basecase, lambda_divide, lambda_conquer, lambda_solvecase);
^
D&C.cpp:67:92: note: candidate is:
D&C.cpp:10:3: note: template<class A, class B, class C> B divideAndConquer(A, C, A, B, B)
B divideAndConquer(const A x, C basecase, A divide, B conquer, B solvecase)
^
D&C.cpp:10:3: note: template argument deduction/substitution failed:
D&C.cpp:67:92: note: deduced conflicting types for parameter ‘A’ (‘std::basic_string<char>’ and ‘main(int, char**)::__lambda5’)
divideAndConquer(text, lambda_basecase, lambda_divide, lambda_conquer, lambda_solvecase);
代码如下:基本上,我们的想法是使用Divide and Conquer过程在文本中查找目标字符串的实例,但要足够通用以重用此模式来解决其他问题(例如斐波那契数字)。
#include <iostream>
#include <thread>
#include <string>
#include <fstream>
#include <future>
using namespace std;
template <typename A, typename B, typename C>
B divideAndConquer(const A x, C basecase, A divide, B conquer, B solvecase)
{
if (basecase(x))
return solvecase(x);
A probl1 = divide(x,1);
A probl2 = divide(x, 2);
auto sol1f = async(divideAndConquer, probl1, basecase, divide, conquer, solvecase);
B sol2 = divideAndConquer(probl2, basecase, divide, conquer, solvecase);
B sol1 = sol1f.get();
return (conquer(sol1, sol2));
}
int splitOnWhitespaces(const string& text, int half, string direction){
int i=half, N = text.length();
if (direction.compare("forward")==0){
while(text[i]!=' ' && text[i] != '\n' && i < N)
i++;
}
else{
while(text[i]!=' ' && text[i] != '\n' && i >= 0)
i--;
if (i<=0 || i==N)
return -1;
else
return i;
}
}
int main(int argc, char *argv[]){
string text= "Nel mezzo del cammin di nostra vita mi ritrovai per una selva oscura, che la diritta via era smarrita.";
string target = "nel";
int base = 10;
auto lambda_basecase = [base](string text){return text.length()<=base;};
auto lambda_divide= [](string text, int subprobl){
int half = text.length()/2;
half = splitOnWhitespaces(text, half, "forward");
if (half==-1)
half = splitOnWhitespaces(text, half, "backward");
if (half==-1)
throw runtime_error("Error splitting the string: no whitespaces\n");
return ((subprobl==1) ? string(text, 0, half) : string(text, half));
};
auto lambda_conquer = [](int count1, int count2){return count1+count2;};
auto lambda_solvecase = [target](string baseText){
int found = 0;
int start = 0;
int len = target.length();
while(baseText.find(target, start)!=string::npos ){
found++;
int position = baseText.find(target, start);
start = position + len + 1;
}
return found;
};
divideAndConquer(text, lambda_basecase, lambda_divide, lambda_conquer, lambda_solvecase);
return 0;
}
我正在研究模板编程,所以对此问题的任何帮助以及对(好)书籍或网页解释此事的任何参考都将不胜感激。 提前谢谢!
答案 0 :(得分:0)
首先,建议:为模板类型提供比A
,B
,C
更有用(建议使用)的名称,...
因此,您已经为相同的类型标识符提供了相同的类型标识符(A
用于std::string
和lambda函数; B
用于两种不同的lambda类型(并且在计数中,不同的lambda是不同的类型;当使用相同的签名时)和返回值(int
,在你的例子中))。
我建议使用以下版本
template <typename dataT, typename divT, typename conqT, typename baseT,
typename solvT>
auto divideAndConquer (dataT const & x, baseT basecase, divT divide,
conqT conquer, solvT solvecase)
-> decltype(solvecase(x))
{
using retT = decltype(solvecase(x));
if ( basecase(x) )
return solvecase(x);
dataT const probl1 { divide(x, 1) };
dataT const probl2 { divide(x, 2) };
auto sol1f = async<retT(*)(dataT const &, baseT, divT, conqT, solvT)>
(divideAndConquer, probl1, basecase, divide, conquer, solvecase);
retT sol2 { divideAndConquer(probl2, basecase, divide, conquer,
solvecase) };
retT sol1 { sol1f.get() };
return conquer(sol1, sol2);
}