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

can i have unordered function arguments in c++?

本文关键字:函数 参数 无序 C++ 我可以      更新时间:2023-10-16

我想要一个组合函数,它以任何顺序接受多个参数。例如:

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')因为为每个案例创建一个函数是乏味的,尤其是当您有很多参数并且您希望按任何顺序排列它们时。这可能吗?

您可以使用函数模板:

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

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

您可以将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

您有两种方法:

1-你可以重载函数 ->这是一种不好的方式

2-您可以使用模板 ->我推荐它

在其他答案中没有人提到它,所以我只是重申我在评论中所说的。您希望从一组对象构建某些内容,其顺序未指定。我认为你会很好地使用构建器模式的变体

在你的情况下,你不需要抽象构建器。只需有一个累加器对象,其中包含一堆add成员函数,用于要支持的类型。在循环中添加它们,然后从累加器中获取结果。

如果您的类型确实只是基元积分和浮点值,只需写出循环并直接执行加法即可。

你可以重载该函数,但有一个"基"函数,在其他函数中被调用,例如:

// "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;
}

以下内容可能会有所帮助:

它使用模板和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;
}