【问题标题】:variadic template recursion with sizeof..., but compile error: no matching function可变参数模板递归与 sizeof...,但编译错误:没有匹配的功能
【发布时间】:2018-03-05 08:11:21
【问题描述】:

我写了一个可变参数模板来递归打印所有参数:

#include <iostream>
using std::ostream; using std::istream;
using std::cin; using std::cout; using std::endl;

template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
    if (sizeof...(rest)) {
        os << t << ", ";
        return myprint(os, rest...);
    }
    else
        return os << t;
}

int main(int argc, char *argv[]) {
    myprint(cout, "hello");
    return 0;
}

但是当我用g++ -std=c++1y 编译它时,它会抱怨:

error: no matching function for call to ‘myprint(std::ostream&)’
     return myprint(os, rest...);

在函数myprint 中,我检查了sizeof...(rest) 的值。而当为0时,不会调用myprint(os, rest...)。所以我不知道为什么它会调用myprint(std::ostream&amp;)

我也搜索了相关的问题,我发现它需要一个基本案例。但是为什么我需要一个基本案例,而sizeof... 不能在可变参数模板中工作?

对于简单的不定递归情况:

template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
    os << t << ", ";            // print the first argument
    return print(os, rest...);  // recursive call; print the other arguments
}

上面的代码根本无法编译同样的错误。

【问题讨论】:

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


    【解决方案1】:

    对于您使用的if statementstatement-truestatement-false 都必须有效,无论 condition 是否产生truefalse 的结果。

    C++17 起可以使用constexpr if;当condition 的值为false 时,statement-true 将被丢弃。例如

    if constexpr (sizeof...(rest)) {
        os << t << ", ";
        return myprint(os, rest...);
    }
    else
        return os << t;
    

    如果你不能使用C++17,你可以在参数个数只有一个的情况下再添加一个模板重载,以停止递归,例如

    template <typename T>
    ostream &myprint(ostream &os, const T &t) {
        return os << t;
    }
    
    template <typename T, typename... Args>
    ostream &myprint(ostream &os, const T &t, const Args&... rest) {
        os << t << ", ";
        return myprint(os, rest...);
    }
    

    LIVE

    【讨论】:

    • 谢谢。但是编译器是怎么把代码的所有路径都简单的编译出来的呢?也许我的编译器不支持 C++17。
    • @zhenguoli 意思是,即使永远不会执行,语句也必须有效。
    • @zhenguoli 答案已修改。
    • 谢谢。我可能已经明白了。但我的编译器不支持 C++17 功能。那么我可以使可变参数模板工作的唯一方法是构造一个基本案例吗?
    • @zhenguoli 是的。您必须只为一个参数添加重载;停止递归。
    【解决方案2】:

    songyuanyao's answer 解释了为什么无效,并提供了 C++17 的解决方案。或者,您可以在此之前对myprint 有一个基本案例。

    template <typename T>
    ostream &myprint(ostream &os, const T &t) {
        return os << t;
    }
    
    template <typename T, typename... Args>
    ostream &myprint(ostream &os, const T &t, const Args&... rest) {
        os << t << ", ";
        return myprint(os, rest...);
    }
    

    【讨论】:

      猜你喜欢
      • 2011-06-29
      • 2015-07-18
      • 2019-07-27
      • 1970-01-01
      • 1970-01-01
      • 2018-07-31
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      相关资源
      最近更新 更多