C++ 变元模板函数中不同参数类型的递归
考虑下面的代码C++ 变元模板函数中不同参数类型的递归,c++,arguments,variadic-templates,variadic-functions,C++,Arguments,Variadic Templates,Variadic Functions,考虑下面的代码 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
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;
}
模板
void foo(){}//终止版本
模板
无效foo(Arg头,Args…Args){
如果(索引==0){
我认为(至少在C++11和C++14中)不可能开发这种类型的foo()
,因为您不知道正确的返回类型
如果您不想使用std::tuple
,我建议开发一个类型traits来提取第n个类型,并通过SFINAE管理foo()
下面是一个可能的解决方案
#include <iostream>
#include <type_traits>
template <std::size_t, typename...>
struct indexType
{ using type = int; }; // the type of the foo() without argument
template <std::size_t I, typename I0, typename ... Is>
struct indexType<I, I0, Is...>
{ using type = typename indexType<I-1U, Is...>::type; };
template <typename I0, typename ... Is>
struct indexType<0U, I0, Is...>
{ using type = I0; };
template <std::size_t I, typename ... Args>
using indexType_t = typename indexType<I, Args...>::type;
template <std::size_t>
int foo ()
{ return 0; } // termination version: a return type is needed
template <std::size_t I, typename Arg, typename... Args>
auto foo (Arg const & head, Args const & ...)
-> typename std::enable_if<I == 0U, Arg>::type
{ return head; }
template <std::size_t I, typename Arg, typename... Args>
auto foo (Arg const &, Args const & ... args)
-> typename std::enable_if<I != 0U, indexType_t<I-1U, Args...>>::type
{ return foo<I-1U>(args...); }
int main ()
{
std::cout << foo<1U> (1, 3.1415, std::string("Test!")) << std::endl;
std::cout << foo<2U> (1, 3.1415, std::string("Test!")) << std::endl;
std::cout << foo<3U> (1, 3.1415, std::string("Test!")) << std::endl;
}
#包括
#包括
模板
结构索引类型
{using type=int;};//不带参数的foo()的类型
模板
结构索引类型
{using type=typename indexType::type;};
模板
结构索引类型
{使用类型=I0;};
模板
使用indexType_t=typename indexType::type;
模板
int foo()
{return 0;}//终止版本:需要返回类型
模板
自动foo(参数常量和头,参数常量和头)
->typename std::enable_if::type
{返回头;}
模板
自动foo(参数常量&,参数常量&…参数)
->typename std::enable_if::type
{返回foo(args…)}
int main()
{
std::你的方法可能有问题
1.1在foo
确保您了解嵌套调用的返回如何工作。您的foo
调用foo
,它将其(foo
)第一个参数返回到foo
。但是您的foo
不关心foo
的返回,因为它调用了foo
,如下所示:
else {
foo<i-1>(args...);// `i-1` becomes `0`
}
1.2必须在编译时知道返回类型
您可以尝试通过将foo
中的返回值向上传递来修复代码:
else {
return foo<i-1>(args...);// NOTE: type of return value depends on `foo<i-1>`
}
2.2 C++14及以上版本
使用C++14,您也可以使用auto
作为返回类型,但如果不可用,则使用constexpr。解决方法是一种众所周知的习惯用法,使用“实现”递归逻辑的类模板的专门化:
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"
}
模板
结构foo_impl{
static_assert(i>0,“i==0”需要专门化);
模板
静态自动获取(T0,Ts…vs){
返回foo_impl::get(vs.);
}
};
模板
结构foo_impl{
模板
静态自动获取(T0 v0,Ts…){
返回v0;
}
};
模板
自动foo(Ts…vs){
静态断言(i>=0&&i
2.3 C++11及以上版本
对于C++11,您需要指定有点繁琐的尾部返回类型。有关详细信息,请参阅
3最后建议
- 启用并分析编译器警告(
-Wall
是绝对最小值)
- 一旦您熟悉了这些技术,就不要自己实现它。相反,请学习并使用标准解决方案,如
std::tuple
- 小心使用编译时递归。它可能会显著增加编译时间
请启用编译器警告。并非所有路径都返回…->格式错误的代码。返回std::get(std::forward\u as\u tuple(args…)
?您知道如何解决此问题吗?其思想是函数可以处理一组不相关的参数,并以参数类型返回一些结果。Thankx。我知道tuple,但我想自己实现几行。比您更有用。
else {
return foo<i-1>(args...);// NOTE: type of return value depends on `foo<i-1>`
}
template<int i, class Arg, class... Args>
Arg foo(Arg, Args... args) {// <--------- NOTE: must return a value of type `Arg`
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...);
}
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"
}