我对某些代码的工作原理有一个大致的了解,但不确定部分是否多余,或者我是否只是不明白为什么要这样做。这个例子取自这里: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
进行检查?我想我想不出需要这样做的场景,而且我确定不会无缘无故地添加额外的代码。
谢谢!
感谢@igor-tandetnik,问题在评论中得到了回答,但我会在这里关闭它。
两种方法都可以,关键是要声明不要定义。如果只给出声明,则需要额外的模板参数来获取返回类型,但如果给出定义,则可以推导出返回类型,因此不需要额外的模板参数。