没有参数的 C++ 可变参数函数

C++ Variadic functions with no argument

我有多个 classes(FooBar 这里是为了简单起见)

struct Bar {};
struct Foo {};

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

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

在我的代码中,我得到了 Foos 和 Bars 的模板参数包,我应该对它们中的每一个调用 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

它有效,但我觉得它相当混乱。我不得不使用具有部分特化的 class 模板,因为函数模板仅支持完全特化。我也试过了

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

我错过了什么吗?有没有办法让我的可变参数函数在不使用函数参数或 class 模板的情况下工作?

but the compiler fails because it can't figure out that doStuff<>() is actually 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 并且它基于 [= 中的模板包扩展46=] 打电话(或者可能不是假的...再见)。

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

#include <iostream>

template <typename T> 
constexpr std::size_t doSomething ()
 { return sizeof(T); }

template <typename ... Ts>
constexpr int fakeFunc (Ts const & ...)
 { return 0; }

template <typename ... Ts>
constexpr int doStuff ()
 { return fakeFunc( doSomething<Ts>()... ); }


int main()
 {
   constexpr int a { doStuff<char, short, int, long, long long>() };

   (void)a;
 }