如何重载用于枚举的模板函数

How to overload a template function for use with enums?

本文关键字:枚举 函数 用于 何重载 重载      更新时间:2023-10-16

我有很多函数,它们都有相同的名称,但有不同的参数(其中有些是模板,有些不是):

void f(int& a) { ... } // there are a few other arithmetic types as well
void f(bool& a) { ... }
template <class T1, class T2> void f(std::pair<T1, T2>&a) { ... } 
template <class T> void f(T& a) { ... }
// ...

除此之外,我还有一个枚举:

enum MyEnum {
  enumVal1, enumVal2
};

实际上,我认为如果现在调用MyEnum e = enumVal1; f(e);,它会自动调用MyEnum的底层类型的重载。事实并非如此。相反,它会生成一个编译器错误。

现在我想定义一个模板函数,它可以捕获所有枚举并调用相应的函数。

template <class T, std::enable_if_t<std::is_enum<T>{}> * = nullptr>
void f(T &a) { /* cast to std::underlying_type<T> and call f() */ }

不幸的是,由于某些原因,这与现有的f(T& a)产生了歧义。

我该如何解决这个问题?解决方案必须对所有枚举有效(但不适用于类枚举)。

我使用gcc 4.9和clang 3.5编译代码。

SFINAE的使用并不能为部分排序提供更好的版本,而只是确定哪些重载可用。也就是说,对于枚举,f()的两个同样好的候选函数导致歧义。解决这种模糊性的最简单方法是SFINAE两个候选者都是互斥类型集:

template <class T, std::enable_if_t<!std::is_enum<T>{}> * = nullptr>
void f(T &a) {
    // version not applicable for enums
}
template <class T, std::enable_if_t<std::is_enum<T>{}> * = nullptr>
void f(T &a) {
    /* cast to std::underlying_type<T> and call f() */
}

这并不能解决您最初的问题,因为枚举器不是lvalues。请注意,您最初的问题可以通过T&作为参数,而是将TT const&或可能的T&&:enums转换为底层类型来解决,但枚举器标记不是左值,不能绑定到非const引用。

除非有充分的理由不这样做,否则我可能只会选择一个过载:

template <typename T>
void f(T&& a) {
    // ...
}

函数f只接受(非常量)引用:

int main() {
    auto e = enumVal1;
    f(e);
    return 0;
}

因此f(enumVal1)失败。