只接受枚举类型的函数

Function that only accepts enumeration types

伙计,我受不了这个该死的模板没有mo'

假设我有这个功能...

void sort(vector<int>& vec)
{
    // stuff
}

我怎样才能使该函数接受所有枚举类型的向量而不重载它该死的 10 次?

我对模板知之甚少,但正在考虑做这样的事情......(这给了我错误:不允许使用类型名称)

template<typename T, std::enable_if_t<std::is_enum<T>>>
void sort(vector<T>& vec)
{
    // stuff
}

你们非常亲密:

#include <vector>
    
template<typename T, typename =std::enable_if_t<std::is_enum<T>::value>>
void sort(std::vector<T>& vec)
{
    // stuff
}
enum x {};

void foo()
{
    std::vector<x> X;
    std::vector<int> Y;

    sort(X); // Works
    sort(Y); // ERROR
}

使用 C++17,您可以节省一些输入:

template<typename T, typename =std::enable_if_t<std::is_enum_v<T>>>
void sort(std::vector<T>& vec)
{
    // stuff
}

首先:您必须使用 std::is_enum<T> 的值,而不是 class 本身。

其次:计算 std::enable_if_t<std::is_enum<T>::value>voidTenum.

因此,当 T 是一个 enum 时,您的函数将变为

// ..................VVVV  void what ?
template<typename T, void>
void sort(vector<T>& vec)
{
    // stuff
}

可能的解决方案是在左侧添加一个 typename

template<typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
void sort(vector<T>& vec)
{
    // stuff
}

可行,但有一个缺点:如果您必须 enable/disable 只有 sort() 的一个版本,一切顺利。但是如果你想要两个不同的 sort() 函数(比如一个用于枚举,一个用于非枚举)

template<typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
void sort(vector<T>& vec)
{
    // stuff
}

template<typename T, typename = std::enable_if_t<not std::is_enum<T>::value>>
void sort(vector<T>& vec)
{
    // stuff
}

这是行不通的,因为你不能有两个具有相同签名的函数(默认模板 type/value 不会更改签名)和 SFINAE 失败,仅删除默认类型第二个参数,不禁用该函数,只是不允许它在不表达第二个模板参数的情况下匹配。

这个问题的解决方法:让SFINAE在等号左边工作如下

template<typename T,
         std::enable_if_t<std::is_enum<T>::value, std::nullptr_t> = nullptr>
void sort(vector<T>& vec)
{
    // stuff
}

template<typename T,
         std::enable_if_t<not std::is_enum<T>::value, std::nullptr_t> = nullptr>
void sort(vector<T>& vec)
{
    // stuff
}

这样 SFINAE enable/disable 函数,所以两个替代函数可以工作而不会相互干扰。

另一种方法(兼容两个替代函数)是使用 SFINAE enable/disable 返回类型,所以

template<typename T>
std::enable_if_t<std::is_enum<T>::value> sort(vector<T>& vec)
{
    // stuff
}

template<typename T>
std::enable_if_t<not std::is_enum<T>::value> sort(vector<T>& vec)
{
    // stuff
}

一些额外的未请求建议:

  1. 不会在标准库中将您的 classes 和函数命名为 classes/functions;因此,请为您的 sort() 取一个不同的名称,以避免与标准 std::sort()

    发生冲突
  2. 避免using namespace std;,或者真的更可能发生名称冲突(调用sort(),被称为你的sort()std::sort()?)

如果您使用全新的 C++(如果可能,我会推荐)。有一个使用概念 (c++20) 的工作示例。刚刚在 gcc 10

测试
#include <type_traits>
#include <vector>
#include <concepts>

template<typename T> requires std::is_enum<T>::value
void sort(std::vector<T> & vec)
{
        // stuff
}

int main()
{
        enum Mew
        {
            neat,
            ugly
        };

        std::vector<Mew> v;
        sort(v);               //works

        std::vector<int> v_int;
        sort(v_int);           //error here

        return 0;
}