C++模板参数推导/替换失败:

C++ template argument deduction/substitution failed:

本文关键字:替换 失败 参数 C++      更新时间:2023-10-16

我对C++很陌生,我正在体验它的一些功能。特别是,我想实现一个通用的Divide and Conque过程,该过程将"函数代码"作为参数来解决问题。事实上,我想的是,"分治"是一个以为参数的高阶函数

  • 一个函数basecase(),用于测试我们是否达到基本情况
  • 求解基本情况的函数CCD_ 2
  • 将问题分解为两个子问题的函数CCD_ 3
  • 函数CCD_ 4,其获取部分解并从两个解中构建一个解

为了做到这一点,我使用了模板:特别是,类型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 whitespacesn");
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;
}

我现在正在学习模板编程,所以如果有任何关于这个问题的帮助,以及任何关于解释这个问题的(好的)书籍或网页的参考,我将不胜感激。提前谢谢!

首先,建议:为比ABC更有用的模板类型命名(建议使用)。。。

因此,将相同的类型标识符赋予完全不同的事物(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);
}