【问题标题】:How to make template deduce return type of function with variadic arguments如何使用可变参数使模板推断函数的返回类型
【发布时间】:2017-09-25 09:21:39
【问题描述】:

堆栈溢出的某个人编写了一种有趣的方法来将 lambda 或仿函数捕获到您自己的类中。我试图简化它,我想我已经接近但遇到了一些麻烦。他们的例子是:

// 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.

但我尝试不使用 auto 关键字,但我失败了,我想了解 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 参数以便模板可以推断返回类型?这只有在 auto 上才有可能吗?

【问题讨论】:

  • 这可能不正确,但我建议你阅读good c++ book,尤其是一些高级的。像这样在撕裂的 sn-ps 中学习 C++ 非常困难。

标签: c++ templates generics variadic


【解决方案1】:

decltype(e) 采用 表达式 e 并计算出该表达式 的类型。您需要提供一个 表达式 来表示您存储的 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...`
    )
)

live example on wandbox


顺便说一句,您仍然应该在对funcObj 的调用中使用std::forward 参数,因为可能有一些右值引用需要进一步向下传播:

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

【讨论】:

  • 这是我猜到的最后一件事。我正在阅读有关 declval 和 std::forward 的信息。 declval 我有点明白,但其他两个我不明白。有趣的是,您说 declval 创建了对象的“假”版本。
  • @Zebrafish:declval 所做的只是返回一个引用类型。由于std::declval&lt;T&gt;()T{} 在非评估上下文中的替代品,我喜欢认为它是“创建一个假实例”。但它只是返回一个参考:)
  • @Zebrafish:我应该进一步澄清什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
相关资源
最近更新 更多