variadic模板递归与sizeof ...,但编译错误:没有匹配的函数

时间:2017-09-24 05:25:30

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

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

#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&)

我还搜索了相关问题,我发现它需要基本情况。但为什么我需要一个基本案例,而且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
}

上述代码根本无法针对相同的错误进行编译。

2 个答案:

答案 0 :(得分:4)

对于您使用的if statement,无论条件 statement-true statement-false 都必须有效得到truefalse的结果。

从C ++ 17开始,您可以使用constexpr if;当 condition 的值为false时, statement-true 将被丢弃。 e.g。

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

答案 1 :(得分: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...);
}