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

时间:2017-11-15 16:35:19

标签: c++ c++11 templates lambda divide-and-conquer

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

我正在研究模板编程,所以对此问题的任何帮助以及对(好)书籍或网页解释此事的任何参考都将不胜感激。 提前谢谢!

1 个答案:

答案 0 :(得分: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);
 }