C ++如何在没有std :: function的情况下声明函数返回函数?

时间:2014-06-19 01:33:37

标签: c++ c++11 lambda

尝试一些构图想法,我有

#include <iostream>
#include <functional>

using namespace std;

struct A { };
struct B { };
struct C { };

B b4a (A a) {   B b; return b;   }
C c4b (B b) {   C c; return c;   }

template <typename R, typename S, typename T>
function<R(T)> composition
(   R(r4s)(S)
,   S(s4t)(T)   ) 
{   return [=] (T t) {   return r4s (s4t (t));  };  }

int main()
{
    cout << "b4a : " << type_name<decltype(b4a)>() << endl;
    cout << "c4b : " << type_name<decltype(c4b)>() << endl;
    auto c4a = composition<C, B, A> (c4b, b4a);
    cout << "c4a : " << type_name<decltype(c4a)>() << endl;
    auto lb4a = [=] (A a) { B b; return b; };
    auto lc4b = [=] (B b) { C c; return c; };
    auto lc4a = composition<C, B, A>(lc4b, lb4a);
    cout << "lc4a : " << type_name<decltype(lc4a)>() << endl;
}

type_name的定义有点偏离主题,但您可以看到a complete working sample of the above here)。

您可以看到此composition运算符适用于b4a等函数指针和lb4a等lambdas。我想摆脱function<R(T)>的{​​{1}}返回类型,直接声明它的类型,但我不知道如何以任何其他方式表示它的返回类型。试图

composition

R(composition)(T)

R(*composition)(T)

产生R(&composition)(T) ,导致我怀疑它是不可能的。线索?

3 个答案:

答案 0 :(得分:3)

Lambdas有一个独特但未指定的类型。一种可能的解决方法是不使用lambdas,而是创建自己的等效类:

template <typename R, typename S, typename T>
struct Composition {
    R (*r4s)(S);
    S (*s4t)(T);
    R operator()(T t) const { return r4s(s4t(t)); }
};

template <typename R, typename S, typename T>
Composition<R,S,T> composition(R (*r4s)(S),S(*s4t)(T)) 
{   
    return {r4s,s4t};
}

答案 1 :(得分:1)

无法在运行时创建新函数。创建lambda只是创建一个lambda的闭包类型(它是一个类)的实例,但是函数本身是在编译时创建的类operator()

lambda表达式捕获的函数指针r4ss4t成为闭包对象的成员。如果您能够真正创建r4ss4t作为新功能的组合,那么它们将被编入代码&#34;,可以这么说。这种事情在C ++中是不可能实现的。

您应该像在此处一样使用std::function

答案 2 :(得分:1)

@Vaughn Cato's answerLive demo)的通用变量变体:

template <typename...>
class Composition {
    // This "base case" is only used for zero-function compositions.
public:
    void operator () () {}
};

template <typename F, typename... Remainder>
class Composition<F, Remainder...> : private Composition<Remainder...> {
    // This specialization matches all non-zero function compositions.
    using base_t = Composition<Remainder...>;

    F f_;

    // Use tag dispatching to determine if F is the last function in
    // the composition, and should be called with the args, or
    // if there are further functions and f should be called with
    // the result of passing the args on to the other functions.
    using is_last = std::integral_constant<bool, sizeof...(Remainder) == 0>;
    template <typename... Args>
    auto dispatch(std::true_type, Args&&... args) ->
      decltype(f_(std::forward<Args>(args)...)) {
        return f_(std::forward<Args>(args)...);
    }
    template <typename... Args>
    auto dispatch(std::false_type, Args&&... args) ->
      decltype(f_(std::declval<base_t&>()(std::forward<Args>(args)...))) {
        return f_(static_cast<base_t&>(*this)(std::forward<Args>(args)...));
    }

public:
    template <typename T, typename... Args>
    Composition(T&& t, Args&&... args) :
        base_t(std::forward<Args>(args)...),
        f_(std::forward<T>(t)) {}

    template <typename... Args>
    auto operator () (Args&&... args) ->
      decltype(std::declval<Composition&>().dispatch(is_last{}, std::forward<Args>(args)...)) {
        return dispatch(is_last{}, std::forward<Args>(args)...);
    }
};

template <typename... Functions>
inline Composition<typename std::decay<Functions>::type...>
composition(Functions&&... f)
{   
    return {std::forward<Functions>(f)...};
}