有什么优雅的方法吗? (类型参数包)

时间:2019-03-12 01:23:17

标签: c++ templates recursion c++17 variadic-templates

我想创建一个接受类型并通过循环或递归再次调用自身的函数。

我已经在下面尝试过,但是它仅调用了基本函数(使用AModule类调用了基本函数,而没有使用BModule.调用了该函数

class AModule {
};
class BModule {
};

auto main() -> int {
  init<AModule, BModule>()
  return 0;
}

template<typename Module>
void init() {
  // BASE FUNCTION
  // Do something
}

template<typename... Modules>
void init() {
  (init<Modules>(), ...)
}

2 个答案:

答案 0 :(得分:3)

在示例代码中,您使用的是模板折叠,这是一项新的C ++ 17功能,可让您避免递归。

但是,为了避免名称冲突,我建议以不同的方式调用基本版本。说do_something()

template<typename Module>
void do_something() {
  // BASE FUNCTION
  // Do something
}

template<typename... Modules>
void init() {
  (do_something<Modules>(), ...);
}

如果您真的想使用递归方法,可以执行以下操作

template <int = 0>
void init ()
 {
  // stop recursion; do nothing
 }

template <typename Head, typename ... Tail>
void init () 
 {
   // do something with Head

   // recursively call init()
   init<Tail...>();
 }

诀窍是调用init<Tail...>();,直到Tail...不为空,称为Head / Tail...递归版本。

Tail...为空时,init<Tail...>()init<>(),因此Head / Tail...版本不再匹配(不存在{{ 1}}),但与Head版本匹配;因此int = 0变成init<>(),无所事事的情况会停止递归。

答案 1 :(得分:1)

在您的代码中(一旦修复了语法错误),两个init()调用均对1个模板参数有效,因此该调用是模棱两可的。通过进行多次init调用至少需要2个参数,可以消除歧义。

// bogus type that just prints an error message including the type it is parameterized with
template<typename T>
struct printer;

template<typename Module>
void init() {
 printer<Module>{}; // this is an error just to show you that it's getting called with both types
}

// only call this if it's called with 2 or more types, otherwise just use the other init()
template<typename T1, typename T2, typename... Modules>
void init() {
    init<T1>();
    init<T2>();
  (init<Modules>(), ...);
}

class AModule {
};
class BModule {
};

auto main() -> int {
  init<AModule, BModule>();
  return 0;
}

实时:https://godbolt.org/z/D-eh2G