不带参数的C ++ Variadic函数

时间:2019-06-04 20:40:15

标签: c++ variadic-templates variadic-functions template-meta-programming function-templates

我有多个类(为简单起见,这里为FooBar

struct Bar {};
struct Foo {};

和一个采用单个模板参数并根据该类型执行某些操作的函数:

template <typename T>
constexpr void doSomething() { cout << "Am I a Foo? " << is_same<T,Foo>::value << endl; }

在我的代码中,给了FooBar的模板参数包,我应该分别对它们调用doSomething()函数(我确实不在乎功能执行的顺序)。

doStuff<Foo, Bar, Bar>(); // --> True / False / False

到目前为止,我唯一能想到的解决方案是:

template <typename... Ts>
class Doer;

template <>
struct Doer <> {
    static constexpr void doStuff() {}
};

template <typename Head, typename... Tail>
struct Doer <Head, Tail...> {
    static constexpr void doStuff() {
        doSomething<Head>();
        Doer<Tail...>::doStuff();
    }
};

template <typename... Ts>
constexpr void doStuff() {
    return Doer<Ts...>::doStuff();
}

doStuff<Foo, Bar, Bar>(); // --> True / False / False

它可以工作,但是我觉得它很混乱。我必须使用具有部分专业化的类模板,因为功能模板仅支持完全专业化。我也尝试过

constexpr void doStuff() { }

template <typename Head, typename... Tail>
constexpr void doStuff() {
    doSomething<Head>();
    doStuff<Tail...>();   // --> Compile Error
}

但是编译器失败,因为它无法确定doStuff<>()实际上是doStuff()。如果我在可变参数函数中有参数,那么编译器很聪明,可以解决此冲突,因为它应用了模板类型推导:

constexpr void doStuff() { }

template <typename Head, typename... Tail>
constexpr void doStuff(Head arg, Tail... args) {
    doSomething<Head>();
    doStuff(args...);
}

Foo f1;
Bar b1, b2;
doStuff<Foo, Bar, Bar>(f1, b1, b2); // --> True / False / False

我想念什么吗?有没有一种方法可以使我的可变参数函数在不使用函数参数或类模板的情况下工作?

1 个答案:

答案 0 :(得分:6)

  

,但是编译器失败,因为它无法确定doStuff <>()实际上是doStuff()。

template <int = 0>
constexpr void doStuff() { }

template <typename Head, typename... Tail>
constexpr void doStuff() {
    doSomething<Head>();
    doStuff<Tail...>();
}

我的意思是:如果问题是最后,模板可变参数列表为空,则使用默认值的模板参数(完全不同:整数而不是类型)将模板转换为基本形式。

因此,当Tail...为空时,调用doStuff<Tail...>()(即doStuff<>())与doStuff<0>()匹配(考虑第一个函数的默认值),因此请调用基本情况

无论如何:如果可以使用C ++ 17,则可以避免递归,并且使用逗号运算符的功能以及模板折叠功能,您可以简单地编写

template <typename... Ts>
constexpr void doStuff() {
    (doSomething<Ts>(), ...);
}

在C ++ 14中,您可以如下模拟模板折叠

template <typename... Ts>
constexpr void doStuff() {
    using unused = int[];

    (void) unused { 0, ((void)doSomething<Ts>(), 0)... };
}

前面的解决方案也可以在C ++ 11上使用,但不能作为constexpr使用(但doSomething()在C ++ 11中不能为constexpr)。

考虑到您不关心函数的执行顺序,我提出了一个C {11}解决方案,该解决方案维护constexpr,它基于伪函数调用中的模板包扩展(或者可能不是假的...再见)。

但这要求doSomething()constexpr(因此,在C ++ 11中不能为void),并且doStuff()也不能为{{ 1}}

void