枚举类构造函数c ++,如何传递特定值? [英] enum class constructor c++ , how to pass specific value?

查看:59
本文介绍了枚举类构造函数c ++,如何传递特定值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我来自Java,在这里我们可以选择构造器的值。

I came from Java and here we have such option as set value to constuctor.

示例

enum TYPE
{
    AUTO("BMW"),
    MOTOCYCLE("Kawasaki");

    private String mBrandName = "";

    TYPE(final String iBrandName)
    {
        mBrandName = iBrandName;
    }

    public String getBrandName()
    {
        return mBrandName;
    }

    static TYPE getMotocycle()
    {
        return MOTOCYCLE;
    }

    static TYPE getAuto()
    {
        return AUTO;
    }
}

用法

String motoBrand = TYPE.getMotocycle().getBrandName(); // == BMW
String autoBrand = TYPE.getAuto().getBrandName(); // == Kawasaki

因此,想法是可以给构造函数指定值(int,String不管),然后得到它。因此,您具有订单号以及要设置的特定值...

So, idea is that you can give to constructor specific value (int, String whatever) and then get it. So, you have order number as well as specific value that you set to...

问题是来自文档 https://docs.microsoft.com/en-us/cpp/cpp/enumerations-cpp? view = vs-2019 我知道cpp中没有这样的选项,对吗?

Question is, from documentation https://docs.microsoft.com/en-us/cpp/cpp/enumerations-cpp?view=vs-2019 I understood that there is no such option in cpp, is it right?

PS 需要枚举,因为您可以保存所有枚举功能(例如元素计数或按数字获取元素),并且使用构造函数还可以获得更多。

P.S. Reason why I need enum, because you save all enum functionality(like count of elements or get element by number) and additionally you get a little bit more with constructor.

在Java中,我可以通过这种方式获取元素计数 TYPE.values()。length https:// stackoverflow.com/a/17492102/5709159

In Java I can get count of elements this way TYPE.values().length https://stackoverflow.com/a/17492102/5709159

在Java中,我可以通过数字方式获取元素 TYPE.values()[序数] https://stackoverflow.com/a/609866/5709159

In Java I can get element by number this way TYPE.values()[ordinal] https://stackoverflow.com/a/609866/5709159

推荐答案

C ++不是Java!每种语言都有自己的技巧,非常适合该语言。不要试图模仿一种语言的完美构造,而要用另一种语言来构造相同(但已损坏)的构造。

C++ ain't Java! Every language has its own techniques which are a good fit with the language. Don't try to mimic a perfectly fine construct of one language in the same (but broken) construct in a different language.

这是我将如何解决您的问题C ++:

Here is how I would solve your issue in C++:

 // Define the actual enumeration
 enum class [[nodiscard]] Vehicle : unsigned char
 {
     CAR,
     MOTORCYCLE,
     SIZE [[maybe_unused]]
 };

// Convert your enumeration to a string (view)
#include <cassert>
#include <string_view>
[[nodiscard]] constexpr auto to_string(Vehicle v) noexcept -> std::string_view {
  assert(v != Vehicle::SIZE);
  switch (v) {
    case Vehicle::CAR:
      return "Car";
    case Vehicle::MOTORCYCLE:
      return "Motorcycle";
  }
}

要使用它,您可以执行以下操作: / p>

To use it, you can do something like:

 for (unsigned char c = 0; c < static_cast<unsigned char>(Vehicle::SIZE); ++c)
        std::cout << to_string(static_cast<Vehicle>(c)) << std::endl;

每次都写这个有点麻烦,但是,您可以编写自己的模板类来帮助遍历它。例如:

Writing this every time is a bit cumbersome, however, you could write your own template class that helps with iterating over it. For example:

#include <type_traits>
// The generic stuff you only write once
// Assumes you don't assign any values to your enumeration by hand + it ends on
// 'SIZE' (unless a second argument was passed if a different name was used)
template <typename TEnumeration, TEnumeration TSize = TEnumeration::SIZE>
class [[nodiscard]] EnumRange final {
  using type = std::underlying_type_t<TEnumeration>;

 public:
  // The iterator that can be used to loop through all values
  //
  class [[nodiscard]] Iterator final {
    TEnumeration value{static_cast<TEnumeration>(0)};

   public:
    constexpr Iterator() noexcept = default;
    constexpr Iterator(TEnumeration e) noexcept : value{e} {}

    constexpr auto operator*() const noexcept -> TEnumeration { return value; }
    constexpr auto operator-> () const & noexcept -> const TEnumeration* {
      return &value;
    }
    constexpr auto operator++() & noexcept -> Iterator {
      value = static_cast<TEnumeration>(1 + static_cast<type>(value));
      return *this;
    }

    [[nodiscard]] constexpr auto operator==(Iterator i) -> bool { return i.value == value; }
    [[nodiscard]] constexpr auto operator!=(Iterator i) -> bool { return i.value != value; }
  };

  constexpr auto begin() const noexcept -> Iterator { return Iterator{}; }
  constexpr auto cbegin() const noexcept -> Iterator { return Iterator{}; }

  constexpr auto end() const noexcept -> Iterator { return Iterator{TSize}; }
  constexpr auto cend() const noexcept -> Iterator { return Iterator{TSize}; }

  [[nodiscard]] constexpr auto size() const noexcept -> type {
    return static_cast<type>(TSize);
  }
};

用法:

#include <iostream>
int main(int, char**) {
  auto range = EnumRange<Vehicle>{};
  std::cout << static_cast<int>(range.size()) << std::endl;
  for (auto v : range) std::cout << to_string(v) << std::endl;
}

如您在第一个测试代码中所见,您可以使用数值使用 static_cast 进行枚举。但是,它假定您具有一些对于枚举有效的值。在范围相同的假设下,我们可以编写自己的选中变体:

As you saw in the first test code, you can go from a numeric value to an enumeration by using static_cast. However, it assumes that you have some value that is valid for the enumeration. With the same assumptions of the range, we can write our own checked variant:

#include <stdexcept>
#include <type_traits>

template <typename TEnumeration, TEnumeration TSize = TEnumeration::SIZE>
[[nodiscard]] constexpr auto checked_enum_cast(
    std::underlying_type_t<TEnumeration> numeric_value) noexcept(false)
    -> TEnumeration {
        using type = std::underlying_type_t<TEnumeration>;
  if constexpr (std::is_signed_v<type>)
    if (numeric_value < 0) throw std::out_of_range{"Negative value"};

  if (numeric_value >= static_cast<type>(TSize)) throw std::out_of_range{"Value too large"};

  return static_cast<TEnumeration>(numeric_value);
}

要使用此功能,您可以编写:

To use this, you can write:

  try {
    std::cout << to_string(checked_enum_cast<Vehicle>(1)) << std::endl;
    std::cout << to_string(checked_enum_cast<Vehicle>(2)) << std::endl;
  } catch (const std::out_of_range& e) {
    std::cout << e.what() << std::endl;
  }

注意:如果一个人生活在一个无例外的世界中,一个人可能会返回 std :: nullopt 并将返回类型更改为 std :: optional< TEnumeration>

Note: If one would live in an exception-free world, one could return std::nullopt and change the return type to std::optional<TEnumeration> instead.

所有代码组合+在Compiler Explorer中执行

请注意,迭代器可以优化,但是,我不是细节专家。 (对于循环来说,没关系,如果您想将其用于算法,则可以)

Please note that the iterator can be refined, however, I ain't an expert in the details. (and for looping, it doesn't matter, if you ever want to use it for an algorithm it could)

这篇关于枚举类构造函数c ++,如何传递特定值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆