【问题标题】:How to specialize a function using enum如何使用枚举专门化一个函数
【发布时间】:2021-09-13 14:16:25
【问题描述】:

我正在尝试重构一些代码。基本上是一个基于枚举的状态机。 有很多 switch 语句和函数以不同的名称和歧义被调用。

由于他们强迫我保留枚举,我想使用模板重构它。基本上我想使用模板来实现多态性。由于状态有限,应该有一种方法,但我找不到最好的方法。

#include <iostream>

enum class AnimalType
{
    Dog,
    Cat
};

template<AnimalType T>
void Foo()
{
    std::cout << "Unknown animal\n";
}

template<>
void Foo<AnimalType::Dog>()
{
    std::cout << "I'm a dog\n";
}

template<>
void Foo<AnimalType::Cat>()
{
    std::cout << "I'm a cat\n";
}

int main()
{
    AnimalType CurrentAnimal = AnimalType::Dog;
    // Foo<CurrentAnimal>(); Won't compile
    return 0;
}

【问题讨论】:

  • 改用Tag dispatch
  • 如果您需要运行时调度,那么此解决方案可能会稍微简化问题,但无法解决问题。考虑类似std::map&lt;AnimalType, std::function&lt;void()&gt;&gt; 或类似的东西。您一定需要某种类型的对象,可以将值映射到特定函数。如果有运行时组件,您不能完全依赖编译器功能,例如模板或重载解析。

标签: c++ templates enums


【解决方案1】:

您需要一个编译时可评估的常量,这将起作用

int main()
{
    constexpr auto CurrentAnimal = AnimalType::Dog;
    Foo<CurrentAnimal>();
    return 0;
}

或直接使用

Foo<AnimalType::Dog>();  

注意:您不能使用您的构造在运行时做出决定。 模板只会导致编译时多态

【讨论】:

    【解决方案2】:

    正如@P Kramer的回答所提到的:

    注意:您不能使用您的构造在运行时做出决定。模板只会导致编译时多态。

    您不能这样做,但您可以使用 Compile-Time Dispatch 和 runtime 参数,方法是将所需值作为参数传递,同时它们由 Function Template Specialization 分隔。例如将您的枚举值转换为实际类型:

    struct animal_t
    {
        std::string const name;
        explicit animal_t(std::string const& name_)
            : name(name_)
        {
        }
        auto operator()() const
        {
            return name;
        }
    };
    
    struct dog_t final : animal_t
    {
        using animal_t::animal_t;
    };
    
    struct cat_t final : animal_t
    {
        using animal_t::animal_t;
    };
    

    他们可以专门化功能模板:

    /*!
     *
     * Other Programmer(s) interface
     *
     */
    template<typename Animal>
    auto function(Animal const&)
    {
        assert(false);
    }
    
    /*!
     *
     * Implementation
     *
     */
    template<>
    auto function(cat_t const& animal)
    {
        return animal();
    }
    template<>
    auto function(dog_t const& animal)
    {
        return animal();
    }
    

    现在,您库的用户(其他程序员)可以轻松地与它进行交互,例如通过 GUI 库:

    QObject::connect(button1, &QPushButton::clicked, &application, [] {
        cat_t cat("Some Cat");
        auto const message = QString::fromStdString(function(cat));
        QMessageBox::information(nullptr, " ", message);
    });
    QObject::connect(button2, &QPushButton::clicked, &application, [] {
        dog_t dog("Some Dog");
        auto const message = QString::fromStdString(function(dog));
        QMessageBox::information(nullptr, " ", message);
    });
    

    结果: 仅用于复制/过去:runtime_dispatch_v1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 2012-09-25
      • 2015-07-05
      • 2011-05-31
      • 1970-01-01
      相关资源
      最近更新 更多