【问题标题】:(C++11) Variadically templated function fowards to another(C++11) Variadic Ally 模板函数转发到另一个
【发布时间】:2014-07-05 09:22:51
【问题描述】:

我正在尝试将我的尾巴从 parser 转发到 add_option,但 GCC 不允许这样做:

// Templated constructor
template <typename H = std::string, typename... T>
parser(H head, T... tail) {
    /* Add an option */
    add_option(std::forward<T>(tail)...);
}

// Base case
void add_option(std::string head) {
    /* Add an option */
}

// Recursive case
template <typename H = std::string, typename... T>
void add_option(H head, T... tail) {
    add_option(tail...);
}

相反,GCC 给了我这个错误:

parser.h: In instantiation of ‘void parser::add_option(H, T ...) [with H = const char*; T = {}]’:
parser.h:16:4:   required from ‘parser::parser(H, T ...) [with H = const char*; T = {const char*}]’
parser.cpp:7:26:   required from here
parser.h:24:4: error: no matching function for call to ‘parser::add_option()’
    add_option(tail...);
    ^
parser.h:24:4: note: candidates are:
parser.h:18:8: note: void parser::add_option(std::string)
   void add_option(std::string head) {
        ^
parser.h:18:8: note:   c1andidate expects 1 argument, 0 provided
parser.h:22:8: note: template<class H, class ... T> void parser::add_option(H, T ...)
   void add_option(H head, T... tail) {
        ^
parser.h:22:8: note:   template argument deduction/substitution failed:
parser.h:24:4: note:   candidate expects 2 arguments, 0 provided
    add_option(tail...);
    ^
Makefile:2: recipe for target 'parser' failed
make: *** [parser] Error 1

谁能告诉我我在这里做错了什么?我该如何解决这个问题?

【问题讨论】:

  • 试试这个:void add_option() {}
  • 你在两个add_options 中都有严格的std::string 参数要求,但你只能递归地传递泛型类型T 参数。
  • 您希望add_option(string) 终止递归 - 但您传递的实际参数是const char*,而不是string,模板化的add_option&lt;const char*&gt; 是更好的匹配。
  • @IgorTandetnik 你的建议奏效了。如果您可以将此扩展为答案,我会将其标记为已解决。
  • 我的建议?但我实际上并没有提出任何建议。我只是试图解释你看到的行为。

标签: c++ gcc c++11 variadic-templates perfect-forwarding


【解决方案1】:
struct parser {
  template <typename... Ts>
  parser(std::string head, Ts... ts) {
    add_options(std::move(head), std::forward<Ts>(ts)...);
  }

  // Base case
  void add_options(std::string head) {
    // I assume we store head somewhere.  `std::move` from it
    // if we don't directly store it, replace all std::string with std::string const&
    std::cout << "option: " << head.c_str() << "\n";
  }

  // Recursive case.  Make 2+ arguments explicit (probably not needed, but I like it)
  template <typename T0, typename... Ts>
  void add_options(std::string head, T0&& t0, Ts&&... ts) {
    add_options(std::move(head));
    add_options(std::forward<T0>(t0), std::forward<Ts>(ts)...);
  }
};

int main() {
  parser parse("hello", "world");
}

live example

【讨论】:

  • 虽然我不确定为什么这个问题被否决了,但我真的很喜欢你的回答。非常感谢!
  • @Chiru 如果你的解析器只能接受可变数量的字符串参数,你应该使用va_list。如果您事先知道类型,则可变参数模板是多余的。
  • @RedAlert 感谢您的参考!
  • @chiru 不,使用 std::initializer_list&lt;std::string&gt; 而不是 C 风格的可变参数。
  • @redalert 不,不要使用 C 风格的变量,至少不要随便。
猜你喜欢
  • 2019-01-16
  • 2015-03-08
  • 1970-01-01
  • 2015-12-27
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多