是否可以调用具有不同数量的参数的函数,并传递相同的参数包

时间:2018-01-14 17:41:29

标签: c++ templates parameter-passing c++14 variadic-templates

例如说我有两个简单的功能:

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可以是编译时常量,而不是运行时参数。

3 个答案:

答案 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);
}

这里的想法是,从varArgscallImpl的调用将根据布尔值的不同而被调度。为此,我们需要将布尔值提升为不同的类型,这就是为什么我说布尔值需要是模板参数而不是值。实例: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);
 }