我可以在c ++中使用无序函数参数吗?

时间:2013-12-29 16:23:18

标签: c++

我想要一个能够以任何顺序获取多个参数的组合功能。 例如:

int combine(int a, float b, char c)
{
    return a+b+c;
}

这只是我想要做的一个例子,但我希望能够使用任何参数顺序调用此函数:combine(1,2.5,'c')combine('c', 1 2.5)combine(2.5,1,'c') 因为为每个案例创建一个函数是很乏味的,特别是当你有很多参数并且你想要任何顺序时。 这有可能吗?

6 个答案:

答案 0 :(得分:6)

您可以使用功能模板:

template <typename T1, typename T2, typename T3>
int combine(T1 a, T2 b, T3 c)
{
    return a+b+c;
}

请注意,abc可以是加法表达式a+b+c有效的任何类型。

答案 1 :(得分:5)

您可以将combine()设为功能模板

template <typename T0, typename T1, typename T2>
int combine(T0 a0, T1 a1, T2 a2) {
    return a0 + a1 + a2;
}

如果要限制可以传递的类型,可以使用SFINAE添加约束。将参数限制为charintfloat类型,尤其是在允许标准转换的情况下,并非完全无关紧要。我认为它看起来像这样:

#include <type_traits>

template <typename T>
struct is_allowed
    : std::integral_constant<bool,
          std::is_convertible<T, char>::value
          || std::is_convertible<T, int>::value
          || std::is_convertible<T, float>::value> {
};
template <typename T0, typename T1, typename T2>
typename std::enable_if<
    is_allowed<T0>::value && is_allowed<T1>::value && is_allowed<T2>::value,
int>::type combine(T0 a0, T1 a1, T2 a2) {
    return a0 + a1 + a2;
}

如果您确实想要保留小数部分(如果存在),您可能需要查看std::common_type<T0, T1, T2>::type的返回类型。

答案 2 :(得分:0)

你有两种方式:

1 - 您可以重载该功能 - &gt;这是一个糟糕的方式

2 - 你可以使用模板 - &gt;我推荐它

答案 3 :(得分:0)

您可以重载该函数,但只有一个“base”函数可以在其他函数中调用,例如:

// "base" function:
int combine(int a, float b, char c)
{
    return a+b+c;
}

// define "forwarders" for reordered function types:
inline int combine(float b, int a, char c) { return combine(a, b, c); }
inline int combine(int a, char c, float b) { return combine(a, b, c); }
inline int combine(float b, char c, int a) { return combine(a, b, c); }
inline int combine(char c, int a, float b) { return combine(a, b, c); }
inline int combine(char c, float b, int a) { return combine(a, b, c); }

正如您在评论中告诉我们的那样,您希望通过另外三种类型的组合来进一步超载这一点;因此,您可以考虑在宏中包装定义重载的五行:

#define OVERLOAD_REORDERED(Treturn, functionName, T1, T2, T3)                \
    inline Treturn functionName(T2 b, T1 a, T3 c) { return functionName(a, b, c); } \
    inline Treturn functionName(T1 a, T3 c, T2 b) { return functionName(a, b, c); } \
    inline Treturn functionName(T2 b, T3 c, T1 a) { return functionName(a, b, c); } \
    inline Treturn functionName(T3 c, T1 a, T2 b) { return functionName(a, b, c); } \
    inline Treturn functionName(T3 c, T2 b, T1 a) { return functionName(a, b, c); } \

然后只写:

int combine(int a, float b, char c)
{
    return a+b+c;
}
OVERLOAD_REORDERED(int, combine, int, float, char)

由于您可能将其拆分为声明(.h)和定义(.cpp),因此您可以将宏调用放在标题中,如下所示:

// .h:
int combine(int a, float b, char c);
OVERLOAD_REORDERED(int, combine, int, float, char)

// .cpp:
int combine(int a, float b, char c)
{
    return a+b+c;
}

答案 4 :(得分:0)

在其他答案中没有人提到它,所以我只想重申我在评论中说的话。 您想要从一组对象构建一些东西,其顺序未指定。我认为你对builder pattern

的变体做得很好

您的案例中不需要抽象构建器。只需要一个带有一堆add成员函数的累加器对象,用于您想要支持的类型。在循环中添加',然后从累加器中获取结果。

如果你的类型确实只是基本积分和浮点值,只需写出循环并直接进行加法。

答案 5 :(得分:0)

以下可能会有所帮助:

它使用模板和SFINAE。

这个SFINAE只需要每种类型一次。

template <typename T, typename ...Ts> struct count_type;

template <typename T, typename Tail, typename ...Ts>
struct count_type<T, Tail, Ts...>
{
    constexpr static int value = std::is_same<T, Tail>::value + count_type<T, Ts...>::value;
};
template <typename T> struct count_type<T>
{
    constexpr static int value = 0;
};

template <typename T0, typename T1, typename T2>
typename std::enable_if<count_type<int, T0, T1, T2>::value == 1
               && count_type<float, T0, T1, T2>::value == 1
               && count_type<int, T0, T1, T2>::value == 1, int>::type
combine(T0 a0, T1 a1, T2 a2) {
    return a0 + a1 + a2;
}