CRTP 中的返回类型推导是否需要不同的模板参数?

问题描述 投票:0回答:1

我对某些代码的工作原理有一个大致的了解,但不确定部分是否多余,或者我是否只是不明白为什么要这样做。这个例子取自这里:https://github.com/pytorch/pytorch/blob/31f311a816c026bbfca622d6121d6a7fab44260d/torch/csrc/autograd/custom_function.h#L96

考虑以下 CRTP 场景:我想实例化在别处跟踪的各种函数(即捕获用于创建计算图的参数):

#include <iostream>

template <typename X, typename... Args>
using forward_t = decltype(X::forward(std::declval<Args>()...));

template <typename T>
struct Function {
    template <typename... Args>
    static auto apply(Args &&...args) {
        using forward_return_t = forward_t<T, Args...>;
        // Do something with params before calling forward ...
        forward_return_t output = T::forward(std::forward<Args>(args)...);
        return output;
    }
};

struct Addition : public Function<Addition> {
    static int forward(int lhs, int rhs) {
        return lhs + rhs;
    }
};

struct Subtraction : public Function<Subtraction> {
    static double forward(double lhs, double rhs) {
        return lhs - rhs;
    }
};

int main() {
    auto add_value = Addition::apply(10, 15);
    std::cout << add_value << std::endl;    // 25
    auto sub_value = Subtraction::apply(10.5, 15.0);
    std::cout << sub_value << std::endl;    // -4.5
}

编译 (-std=c++14/17/20) 并按预期工作。然而,来自 libtorch 代码库的签名是这样的:

template <class T>
struct Function {
  // We need to use a different template parameter than T here because T will
  // inherit from Function, and when Function<T> is instantiated, T::forward
  // is not declared yet.
  // The enable_if check is to ensure that the user doesn't explicitly provide
  // the parameter X.
  template <typename X = T, typename... Args>
  static auto apply(Args&&... args)
      -> std::enable_if_t<std::is_same<X, T>::value, forward_t<X, Args...>>;
};

推理(根据我的理解)是我们需要类型

T
来知道值
forward_t
,所以它是前面的模板类型参数的一部分。

我想我的问题是 1) 添加的

typename X = T
是否多余,因为没有它我的代码似乎工作得很好,以及 2) 如果
std::enable_if
的代码没有它会失败,为什么要用
forward_t
进行检查?我想我想不出需要这样做的场景,而且我确定不会无缘无故地添加额外的代码。

谢谢!

c++ crtp libtorch
1个回答
0
投票

感谢@igor-tandetnik,问题在评论中得到了回答,但我会在这里关闭它。

两种方法都可以,关键是要声明不要定义。如果只给出声明,则需要额外的模板参数来获取返回类型,但如果给出定义,则可以推导出返回类型,因此不需要额外的模板参数。

© www.soinside.com 2019 - 2024. All rights reserved.