gpt4 book ai didi

c++ - 不同参数类型的可变参数模板函数的递归

转载 作者:行者123 更新时间:2023-11-30 05:08:27 28 4
gpt4 key购买 nike

考虑下面的一段代码

template <int INDEX>
void foo() { } // termination version

template <int INDEX, typename Arg, typename... Args>
void foo(Arg head, Args... args) {

if (INDEX == 0) {


cout << head << endl;
}

else {


foo <INDEX-1 > (args...);

}

}

int main() {

foo<1> (1, 3.1415);

return 0;
}

代码按预期编译并输出 3.1415。

但是,下面的简单代码可以正常编译,但始终输出 1。您对此有任何修复吗?

template <int INDEX>
void foo() { } // termination version

template <int INDEX, typename Arg, typename... Args>
Arg foo(Arg head, Args... args) {
if (INDEX == 0) {

return head;

}

else {


foo <INDEX-1 > (args...);

}



}



int main() {

cout<<foo<1> (1, 3.1415,"Test!");

return 0;
}

换句话说,我如何递归调用具有不同参数类型的可变参数模板函数?

最佳答案

1 你的方法有问题

1.1 缺失 returnfoo<1>

确保您了解 return来自嵌套调用的作品。你的foo<1>电话 foo<0>它将其( foo<0> 的)第一个参数返回给 foo<1> .但是你的foo<1>不关心foo<0>返回是因为它调用了 foo<0>像这样:

else {
foo<i-1>(args...);// `i-1` becomes `0`
}

编译器知道你这里有问题:哪个值应该foo<1>foo<0>得到返回后返回(哪个被忽略了)?它必须返回一个与其第一个参数类型相同的值,但它在到达结束前永远不会返回 } .

正如评论中所指出的,您应该打开编译器警告来检测此类问题。在这种情况下, -Wall (GCC documentation on warning options)sufficient for GCC and clang to warn you (online demo) , 但有更多可用的警告。如果您的文件名显示为 main.cpp和结束}找到第 23 行,第 1 列,编译器警告可以读取

main.cpp: In function ‘Arg foo(Arg, Args ...) [with int INDEX = 1; Arg = int; Args = {double, const char*}]’:
main.cpp:23:1: warning: control reaches end of non-void function [-Wreturn-type]


}
^

1.2 编译时必须知道返回类型

您可能会尝试通过传递 foo<0> 的返回值来修复您的代码上栈:

else {
return foo<i-1>(args...);// NOTE: type of return value depends on `foo<i-1>`
}

但是,这失败了,因为 foo<1>已声明返回与其第一个参数类型相同的值:

template<int i, class Arg, class... Args>
Arg foo(Arg, Args... args) {// <--------- NOTE: must return a value of type `Arg`

2 修复您自己的递归实现

2.1 C++17及以上

对于 C++17,您可以使用 auto作为返回类型与 constexpr if 一起实现递归如下:

template<size_t i, class T0, class... Ts>
auto foo(T0 v0, Ts... vs) {
static_assert(i < 1u + sizeof...(Ts));
if constexpr(0u == i) return v0;// <------ NOTE: must be `if constexpr` (C++17)
else return foo<i-1u>(vs...);
}

2.2 C++14 及以上

对于 C++14,您还可以使用 auto作为返回类型,但是 constexpr if不可用。解决方法是一个众所周知的习惯用法,并使用“实现”递归逻辑的类模板的特化:

template<int i>
struct foo_impl {
static_assert(i > 0, "the case `i == 0` requires a specialization");

template<class T0, class... Ts>
static auto get(T0, Ts... vs) {
return foo_impl<i-1>::get(vs...);
}
};

template<>
struct foo_impl<0> {
template<class T0, class... Ts>
static auto get(T0 v0, Ts...) {
return v0;
}
};

template<int i, class... Ts>
auto foo(Ts... vs) {
static_assert(i >= 0 && i < sizeof...(Ts), "index range: [0, size)");
return foo_impl<i>::get(vs...);// forward to "implementation"
}

2.3 C++11 及以上

使用 C++11,您需要指定尾随返回类型,这有点乏味。参见 max66's answer了解详情。

3 最终建议

  • 启用并分析编译器警告(-Wall 是绝对最小值)。
  • 一旦您熟悉了这些技术,就不要自己实现。相反,学习和使用标准解决方案,如 std::tuple .
  • 谨慎使用编译时递归。它可能会显着增加您的编译时间。

关于c++ - 不同参数类型的可变参数模板函数的递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46837565/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com