【问题标题】:Composition of functions from the standard来自标准的功能组成
【发布时间】:2020-12-31 08:14:18
【问题描述】:

我正在尝试创建一个函数“compose”,返回作为参数给出的可调用对象的组合。

在数学中,应该是这样的:

F = h(g(f(x)))

这里是 C++ 的实现:

template <typename F>
auto compose(F&& f)
{
    return[f = std::forward<F>(f)](auto&&... args){
        return f(std::forward<decltype(args)>(args)...);
    };
}

template <typename F, typename G, typename... Functions>
auto compose(F&& f, G&& g, Functions&&... functions)
{
    return compose(
        [f = std::forward<F>(f), g = std::forward<G>(g)](auto&&... args)
        {
            return f(g(std::forward<decltype(args)>(args)...));
        },
        std::forward<Functions>(functions)...);
}

如果我提供 lambda 函数作为参数,这就像一个魅力:

auto f = compose(
    [](auto value) { return std::sin(value); },
    [](auto value) { return std::asin(value); }
);

但是,如果我直接使用标准中的重载函数(没有将它们封装在 lambda 中),编译器将无法推断选择哪个重载来实例化模板:

auto g = compose(
    std::sin,
    std::asin
);

这里使用 Microsoft C++ 编译器的错误:

error C2672: 'compose': no matching overloaded function found
error C2783: 'auto compose(F &&,G &&,Functions &&...)': could not deduce template argument for 'F'
message : see declaration of 'compose'
error C2783: 'auto compose(F &&,G &&,Functions &&...)': could not deduce template argument for 'G'
message : see declaration of 'compose'
error C2780: 'auto compose(F &&)': expects 1 arguments - 2 provided
message : see declaration of 'compose'

有没有办法在创建组合函数时说明我们想要使用的函数类型(std::sin 和 std::asin)?

【问题讨论】:

  • 我不认为有什么好办法。有些人使用宏方便地将函数包装在宏中。
  • 为什么不立即传入你的数据类型,以便你可以使用呢?例如。 compose&lt;double&gt;(...)。那么应该像魅力一样工作

标签: c++ functional-programming


【解决方案1】:

传递(double (&amp;)(double)) std ::sin怎么样?

【讨论】:

【解决方案2】:

当你用重载函数调用compose时,比如std::sin,编译器无法推断出你想要的函数的类型。

出现解决问题的一种方法是形成一个指向函数特定重载的指针/引用,例如:

// wrong, though it might appear to work
auto g = compose(
    static_cast<double(&)(double)>(std::sin),
    static_cast<double(&)(double)>(std::asin)
);

但这是不正确的,因为您不能从std:: 获取未明确标记为可寻址 的函数地址。正确的做法实际上是您问题中将函数调用包装在 lambda 中的版本(在构造 f 时)。

请注意,转换为指针/引用以消除重载的歧义对于您自己的重载集或std:: 中标记为可寻址的函数都可以正常工作。

【讨论】:

  • std:: sin (double) 是从extern "C" sin 导入的,并且是可寻址的。
  • @ChristopherYeleighton 嗯,也许是这样,但这只是意味着::sin 是可寻址的,对吧?我认为c++版本仍然不可寻址,至少我找不到它说std::sin是可寻址的。
  • 我认为std ::sin (double)::sin 的别名?
  • 嗯,我不这么认为,但我不确定。我得调查一下。
  • 不是,cmath 和 math.h 不同。见cppreference
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多