【问题标题】:C++ specialise function on enum枚举上的 C++ 特化函数
【发布时间】:2016-08-14 19:19:24
【问题描述】:

是否可以在 enum 上专门化模板函数?

我已经注意到 here 一个模板函数可以被禁用,如果它不是一个枚举,但这是否可能同时仍然允许其他类型?

下面的示例显示了intfloatenum 的特化(它无法编译,因为它试图重载enum 版本而不是特化它)。我觉得我遗漏了一些明显的东西。

请注意,我希望专注于 any 枚举,而不仅仅是一个命名的枚举(示例中为EAnEnum

#include <iostream>

enum class EAnEnum
{
    Alpha,
    Beta,
};

template<typename T>
void MyFunc();

template<>
void MyFunc<int>()
{
    std::cout << "Int" << std::endl;
}

template<>
void MyFunc<float>()
{
    std::cout << "Float" << std::endl;
}

// MyFunc<Enum>
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type MyFunc()
{
    std::cout << "Enum" << std::endl;
}

int main()
{
    MyFunc<EAnEnum>();
    return 0;
}

【问题讨论】:

  • 您正在尝试执行函数模板的部分特化。没有这样的事情——你可以做完全的专业化,或者重载。一种可能的方法 - 将您的特定于枚举的实现放入主模板中,可能带有static_assert,该类型实际上是一个枚举。
  • 您要解决的实际问题是什么。不,不是这个问题,而是你认为答案是这种专业化的问题。
  • 一般来说,函数专业化并不是解决几乎所有你试图用它解决的问题的最佳方法。简而言之,会有更好的方法。解决方案最终变得脆弱而尴尬。描述真正的问题,用另一种方式解决它。
  • 我在流上使用&gt;&gt; 运算符,我想专门使用它来读取不同于文件中整数的枚举,而不必脱离my_stream &gt;&gt; x &gt;&gt; y &gt;&gt; z; 模式,作为@ 987654332@, ReadEnum() 模式需要。我事先不知道枚举的类型。我同意可能有更好的解决方案,但这个问题仍然是一个思考练习:)

标签: c++ templates c++11 enums specialization


【解决方案1】:

您不能部分特化一个函数,但您可以使用 标签调度
它遵循基于 OP 问题的最小工作示例:

#include <iostream>
#include<type_traits>

enum class EAnEnum
{
    Alpha,
    Beta,
};

template<typename>
struct tag {};

void MyFunc(tag<int>)
{
    std::cout << "Int" << std::endl;
}

void MyFunc(tag<float>)
{
    std::cout << "Float" << std::endl;
}

void MyFunc(tag<EAnEnum>)
{
    std::cout << "Enum" << std::endl;
}

template<typename T>
void MyFunc() {
    MyFunc(tag<std::decay_t<T>>{});
}

int main()
{
    MyFunc<EAnEnum>();
    return 0;
}

您可以轻松添加要转发到正确 MyFunc 的参数包,并且仍然使用此技术来解决您的问题。
当然,您现在可以专攻任何枚举。
您还可以提供后备 MyFunc 为:

template<typename T>
void MyFunc(tag<T>)
{
    std::cout << "Fallback" << std::endl;
}

如果您想要所有可能的枚举类型的后备,您现在可以依赖 SFINAE,因为这些是不同的重载函数:

template<typename T>
std::enable_if_t<std::is_enum<T>::value>
MyFunc(tag<T>)
{
    std::cout << "Fallback for enums only" << std::endl;
}

请注意,您不应直接使用接受 tag 特化作为入口点的 MyFunc 的含义。
这些是内部函数。
改用通用的,如示例所示。

【讨论】:

  • 这是否仍然让我需要明确说明我的枚举名称,如tag&lt;EAnEnum&gt;)
  • @cz 对于那些重载函数,如果需要,您现在可以在 fallbacks 上使用 sfinae。让我编辑问题以澄清这一点。
【解决方案2】:

你不能部分特化一个函数模板,但你可以让它转发到一个类模板。

由于您的函数没有特别简单的参数:

#include <iostream>
#include <type_traits>

namespace impl {
    using namespace std;

    template< class Type, bool is_enum_ = is_enum<Type>::value >
    struct Foo;

    template< class Type >
    struct Foo<Type, true>
    { void func() { cout << "Enum" << endl; } };

    template<>
    struct Foo<int>
    { void func() { cout << "Int" << endl; } };

    template<>
    struct Foo<float>
    { void func() { cout << "Float" << endl; } };

}  // namespace impl

template< class Type >
void foo()
{ impl::Foo<Type>().func(); }

auto main()
    -> int
{
    enum class An_enum
    {
        alpha, beta,
    };

    foo<An_enum>();
    foo<int>();
    foo<float>();
    #ifdef TEST
        foo<char>();    //! Doesn't compile.
    #endif
}

使用参数,您可以通过std::forward 使用“完美转发”(实际上并不是那么完美,但通常已经足够好了)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    相关资源
    最近更新 更多