如何使模板通过变异参数推断返回类型的函数



堆栈溢出上的某人写了一种有趣的方法,可以将lambda或fundor捕获到您自己的课堂中。我试图简化它,我想我很近,但是遇到了一些麻烦。他们的例子是:

// OT => Object Type
// RT => Return Type
// A ... => Arguments
template<typename OT, typename RT, typename ... A>
struct lambda_expression {
    OT _object;
    RT(OT::*_function)(A...)const; // A pointer to a member function, 
                                   // specifically the operator()
    lambda_expression(const OT & object) // Constructor
        : _object(object), 
          _function(&decltype(_object)::operator()) {} // Assigning the function pointer
    RT operator() (A ... args) const {
        return (_object.*_function)(args...);
    }
};

基本上,这使您可以去:

int captureMe = 2;
auto lambda = [=](int a, int b) { return a + b + captureMe;};
lambda_expression<decltype(lambda), int, int, int>(lambda); 

我试图简化这一点,并认为不需要lambda_expression类中包含的指针,因为您可以调用函数对象本身,而不是将指针调用为Operator()。所以我尝试了:

template <typename OT, typename ... Args>   // No Return type specified
struct lambdaContainer
{
    lambdaContainer(OT funcObj) : funcObj(funcObj){ }
    OT funcObj; // No pointer, just the function object.
    auto operator()(Args... args) 
    {
        return funcObj(args...); // Call the function object directly
    }
};

然后类似:

int captureMe = 2;
auto lambda = [=](int a, int b) { return a + b + captureMe; };
lambdaContainer<decltype(lambda), int, int> lam(lambda);
auto i = lam(1, 1);
// i = 4;

我写了这条话:

auto operator()(Args... args) 
    {
        return funcObj(args...); 
    }

显然:

 decltype(auto) operator()(Args... args) //works in C++14 apparently.

但是我尝试没有自动关键字,但我对此感到惨败,我想了解args如何工作。我尝试了:

decltype(funObj(Args...) operator()(Args... args) // this failed
decltype(OT(Args...) operator() (Args... args) // this failed
auto operator() (Args... args) -> decltype(funcObj(Args...)) // this failed
auto operator() (Args... args) -> decltype(OT(Args...)) // this failed

如何扩展ARGS参数,以便模板可以推断出返回类型?这只能使用自动?

decltype(e)采用表达式 e,并评估该 expression 的类型。您需要提供代表您存储的lambda的调用的表达式

auto operator()(Args... args) 
    -> decltype(std::declval<OT>()(std::declval<Args>()...))

在这种情况下,我正在使用std::declval创建可用于扣除目的的对象的"假实例",而无需实际调用任何构造函数。

让我们进一步分解:

-> decltype(
    std::declval<OT>()          // create a fake instance of `OT`
    (                           // invoke it
        std::declval<Args>()... // create a fake instance of each argument 
                                // type, expanding `Args...`
    )
)

wandbox上的实时示例


顺便说一句,您仍然应该std::forward呼叫funcObj中的参数,因为可能有一些 rvalue参考需要进一步传播:

auto operator()(Args... args) 
{
    return funcObj(std::forward<Args>(args)...); 
}

最新更新