没有参数的 C++ 可变参数函数
C++ Variadic functions with no argument
我有多个 classes(Foo
和 Bar
这里是为了简单起见)
struct Bar {};
struct Foo {};
以及一个采用单个模板参数并根据该类型执行某些操作的函数:
template <typename T>
constexpr void doSomething() { cout << "Am I a Foo? " << is_same<T,Foo>::value << endl; }
在我的代码中,我得到了 Foo
s 和 Bar
s 的模板参数包,我应该对它们中的每一个调用 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;
}
我有多个 classes(Foo
和 Bar
这里是为了简单起见)
struct Bar {};
struct Foo {};
以及一个采用单个模板参数并根据该类型执行某些操作的函数:
template <typename T>
constexpr void doSomething() { cout << "Am I a Foo? " << is_same<T,Foo>::value << endl; }
在我的代码中,我得到了 Foo
s 和 Bar
s 的模板参数包,我应该对它们中的每一个调用 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;
}