例如说我有两个简单的功能:
void a(int x)
{
//do something with x
}
void b(int x, float y)
{
// do something with x and y
}
我希望有一个具有可变数量的args的单个函数,它可以根据标志调用上述两个:
template<typename... Args>
void varArgs(bool a_or_b, Args... args)
{
if (a_or_b)
a(args...);
else
b(args...);
}
该标志将告诉我们是否要使用第一个或第二个函数,但是因为模板在编译时被实例化,所以这将不起作用。我读过constexpr if
但是我只能使用c ++ 14,所以我想知道是否还有其他选择?
编辑: bool可以是编译时常量,而不是运行时参数。
答案 0 :(得分:5)
您可以使用constexpr if
执行任何操作,您可以使用标记调度。它看起来像这样:
void a(int x)
{
//do something with x
}
void b(int x, float y)
{
// do something with x and y
}
template <typename ... Args>
void callImpl(std::true_type, Args && ... args) {
a(std::forward<Args>(args)...);
};
template <typename ... Args>
void callImpl(std::false_type, Args && ... args) {
b(std::forward<Args>(args)...);
};
template<bool callA, typename... Args>
void varArgs(Args&&... args)
{
callImpl(std::integral_constant<bool, callA>{}, std::forward<Args>(args)...);
}
int main() {
varArgs<true>(0);
varArgs<false>(0, 0.0);
}
这里的想法是,从varArgs
到callImpl
的调用将根据布尔值的不同而被调度。为此,我们需要将布尔值提升为不同的类型,这就是为什么我说布尔值需要是模板参数而不是值。实例:http://coliru.stacked-crooked.com/a/6c53bf7af87cdacc
答案 1 :(得分:4)
功能重载
如果您只是想根据传递的参数的签名调用参数包,则可以使用相同函数的不同重载来执行此操作:
void a(int x)
{
//do something with x
}
void a(int x, float y)
{
// do something with x and y
}
template<typename... Args>
void dispatcher(Args... args)
{
a(args...);
}
标记调度
如果您想根据布尔值选择函数,并且您将始终有2个参数(1 int
,1 float
),您可以使用模板布尔值来完成和标签发送:
#include <type_traits>
void a(int x)
{
//do something with x
}
void b(int x, float y)
{
// do something with x and y
}
template<bool B, typename... Args>
void disp_impl(std::true_type, Args... args)
{
a(args...);
}
template<bool B, typename... Args>
void disp_impl(std::false_type, Args... args)
{
b(args...);
}
template<bool B, typename... Args>
void dispatcher(Args... args)
{
using type = std::integer_constant<bool, B>;
a(type{}, args...);
}
<强>运行强>
如果您需要运行时选择,则必须采用旧式方式。请记住,所有函数签名都必须有效,因为在编译时不知道分支评估。因此,这仅在将相同的参数传递给函数的所有版本时才有用,并且在编译时不知道布尔值。这依赖于get
描述here的帮助者。
void a(int x)
{
//do something with x
}
void b(int x, float y)
{
// do something with x and y
}
template<typename... Args>
void dispatcher(bool a_or_b, Args... args)
{
if (a_or_b)
a(get<0>(args...));
else
b(args...);
}
答案 2 :(得分:2)
不幸的是,这不是一般解决方案,而是针对您的特定情况量身定制的解决方案。
如果在false情况下第二个值的默认值为几个lambda包装器呢?
template<typename... Args>
void varArgs (bool a_or_b, Args... args)
{
if ( a_or_b )
[](int x, ...){ a(x); }(args...);
else
[](int x, float y = 0.0f, ...){ b(x, y); }(args...);
}
当a_or_b
的值未知编译时,这也应该有用。
如果你可以修改varArgs()
签名,你可以直接使用second-argument-with-default-value技巧并避免使用lambda函数
void varArgs (bool a_or_b, int x, float y = 0.0f, ...)
{
if ( a_or_b )
a(x);
else
b(x, y);
}