模板参数到模板实例类型值的映射的 C++ 习惯用法?

问题描述 投票:0回答:1

我有一个枚举类,比如说

enum class color { Red, Green, Blue, /* etc. */};

我有类模板,

template <color Color> class foo;

现在,我想声明一个数据类型,对于

color
的某些(或全部)可能值,它保存
foo<color>
类型的值;我希望能够在运行时插入和删除此类映射。

所以,我想要类似从 color 到 foo 的 unordered_map 之类的东西,除了对于给定的颜色,映射实际上并不是到任何

foo
,而是到
foo<color>

我能想到的最接近的东西,也很简洁,是

using MyMap = std::tuple<color::Blue, color::Red, color::Green>

(或者可能是每个 foo 的

std::optional
),因此给定颜色,我可以使用
std::get<foo<MyColor>>(my_map));
并且我还可以编写一个在编译时采用实际颜色的 getter:

template <color Color>
foo<Color> get(const MyMap& map)
{ return std::get<foo<Color>>(map); }

但这一切都有点笨拙。我可以做得更好吗?

备注:

  • 如果没有从某些颜色值映射任何内容 - 我不介意确切的行为:它可能是一个异常,返回 nullopt,或者如果您的结构只能在编译时填充,甚至无法编译。
  • 如果您愿意,您可以使用较新的 C++ 语言版本(如果对您有帮助,甚至可以使用 C++26),但我们需要越不古怪越好。
c++ enums mapping stdtuple enum-class
1个回答
0
投票

我会从适应开始

std::variant

#include <variant>

class color_var{
public:
    enum color: std::uint_8{/*list the colors*/};

    color_var(auto&& x) //the actual setter
    :   m_var{std::forward<decltype(x)>(x)}{};

    template<color what>
    friend auto* get(color_var const &that){
        size_t constexpr n{std::to_underlying(what)};
        return holds_alternative<n>(m_var)
             ? std::addressof(get<n>(that.m_var))
             : nullptr;
    };//! get<what>

    friend color to_color(color_var const &that){
       return color{static_cast<uint8_t>(index(that.m_var))};
    };//! to_color

    friend auto& to_variant(color_var const &that)
    { return that.m_var; };

private:
     std::variant</*list of types*/> m_var;
};//! class color_var

提供的构造函数扮演放置/赋值的角色。但这个类不是默认可构造的,因为我不知道首选颜色。您可以设置任何值,颜色将自动调整:

color_var cv = type1_in_list{/*init*/};
assert((to_color(cv)==color_var::color1_in_list));
type2_in_list value2{/*init*/};
cv = value2;
assert((to_color(cv)==color_var::color2_in_list));

当颜色已知时,可以检索指向值的非拥有指针以立即使用:

assert((to_color(cv)==my_color));
assert((get<my_color>(cv)));
use(*get<my_color>(cv));

但最好的用法是访问变体:

auto result = std::visit([](auto& value{
    if constexpr(std::same_as<type1, remove_cvref_t<decltype(value)>)
       return true;
    return false;
}, to_variant(cv));

std::visit
是访问变体最快、最安全、最易读的方式。如果您的类型列表都使用一些常见的鸭子类型功能,那么您实际上不需要 lambda 中的
if
语句。

由于语法清晰,我更喜欢友元函数而不是非虚拟公共成员。但您可以让他们成为会员。

© www.soinside.com 2019 - 2024. All rights reserved.