【问题标题】:C++ variadic function template in std::functionalstd::functional 中的 C++ 可变参数函数模板
【发布时间】:2020-01-25 21:59:17
【问题描述】:

基本上我想将多维积分与此递归相结合。
但问题本身是一个普遍问题。它不是特定于集成的。

#include "math.h"
#include <iostream>
#include <functional>

double f(double x,double y,double z){
    return x+y+z+1;
}

//Base
double redDim(std::function<double(double)> &f){
    return f(0); //a silly integrator for testing
}
// Recursion
template<typename Tfirst=double, typename... Trest>
auto redDim(std::function<double(Tfirst first,Trest... rest)> &f){
    return redDim([=](Trest... R){return redDim([=](double x){return f(x,R...);});});
}

int main(){
    std::cout<<redDim(f)<<std::endl;
    return 0;
}

问题是,编译器说:

c:\C++\templateTutorial\templateTut.cpp: In function 'int main()':
c:\C++\templateTutorial\templateTut.cpp:24:19: error: no matching function for call to 'redDim(double (&)(double, double, double))'
     cout<<redDim(f)<<endl;
                   ^
c:\C++\templateTutorial\templateTut.cpp:12:8: note: candidate: 'double redDim(std::function<double(double)>&)'
 double redDim(std::function<double(double)> &f){
        ^~~~~~
c:\C++\templateTutorial\templateTut.cpp:12:8: note:   no known conversion for argument 1 from 'double(double, double, double)' to 'std::function<double(double)>&'
c:\C++\templateTutorial\templateTut.cpp:17:6: note: candidate: 'template<class Tfirst, class ... Trest> auto redDim(std::function<double(Tfirst, Trest ...)>&)'
 auto redDim(std::function<double(Tfirst first,Trest... rest)> &f){
      ^~~~~~
c:\C++\templateTutorial\templateTut.cpp:17:6: note:   template argument deduction/substitution failed:
c:\C++\templateTutorial\templateTut.cpp:24:19: note:   mismatched types 'std::function<double(Tfirst, Trest ...)>' and 'double(double, double, double)'
     cout<<redDim(f)<<endl;
                   ^
The terminal process terminated with exit code: 1

那么为什么f的类型不符合redDim()的要求呢?
因此,如果我的方法有效,我什至无法测试。
我希望你能帮助我!

【问题讨论】:

标签: c++ templates metaprogramming variadic-templates std-function


【解决方案1】:

函数指针不是std::function。

模板参数推导不做任何类型转换,除了一些基本的情况。

添加一个调用std函数的redim( double(*f)(Args...) )模板。

template<class...Args>
auto redDim( double(*f)(Args...) {
  return redDim( std::function<double(Args...)>{ f } );
}

它应该可以工作。

这可以推导出函数指针的签名。然后它显式转换为 std::function,然后匹配您的其他 redim 函数。

您必须将其他 lambda 表达式显式转换为 std::functions:

// Recursion
template<typename Tfirst, typename... Trest>
auto redDim(std::function<double(Tfirst first,Trest... rest)> f){
  return redDim(
    std::function<double(Trest...)>{
      [=](Trest... R){
        return redDim(
          std::function<double(double)>{
            [=](double x){return f(x,R...);}
          }
        );
      }
    }
  );
}

Live example.

还将最后一个redDim 的参数更改为std::function&lt;double(double)&gt;(不是参考)。或者,const&amp;。

【讨论】:

  • 现在下一个错误是:需要来自 'auto redDim(double (*)(Args ...)) [with Args = {double, double, double}]' 错误: 没有匹配函数调用 'redDim(redDim(std::function) [with Tfirst = double; Trest = {double, double}]::)' return redDim([&](Trest...rest){return redDim([&](double x){return f(x,rest...);});});跨度>
  • @Babalion Live 示例已添加。
【解决方案2】:

根据 Yakk - Adam Nevraumont 的回答,应编译以下代码:

#include "math.h"
#include <iostream>
#include <functional>

double f(double x,double y,double z){
    return x+y+z+1;
}

//Base
double redDim(const std::function<double(double)> &f){
    return f(0); //a silly integrator for testing
}
// Recursion
template<typename Tfirst=double, typename... Trest>
auto redDim(const std::function<double(Tfirst first,Trest... rest)> &f) {

    return redDim(
    std::function<double(Trest...)>{
        [=](Trest... R)->double{return redDim([=](double x){return f(x,R...);});}});
}

template<class...Args>
auto redDim( double(*f)(Args...)) {
  return redDim( std::function<double(Args...)>{ f } );
}

int main(){
    std::cout<<redDim(f)<<std::endl;
    return 0;
}

正如 Yakk 已经指出的,std::function 和函数指针的类型不同。请注意,我还将redDim 的参数类型更改为const std::function&lt;...&gt; &amp;)。您还可以使用 &amp;&amp; 语法传递 rvalue 引用。

【讨论】:

    猜你喜欢
    • 2019-01-18
    • 2019-04-30
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-18
    • 2014-01-19
    相关资源
    最近更新 更多