String-Variable in Enum-Datentyp vorhanden?



  • Hallo zusammen 🙂

    ich bin dabei einen kleinen Code zu schreiben. Hierfür bekomme ich aus einer CAD-Zeichnung eine .txt Datei mit Daten wie beispielsweise das Material eines Drehteils. Diese .txt lese ich aus und überführe die Information in eine string variable. Nun habe ich vorgegebene Materialien mit denen ich weiter arbeiten möchte, z.b. Holz und Metall. Ich möchte nun eher ungern über eine If Abfrage schauen ob das Material des Drehteils einer Vorgabe entspricht, weshalb ich es über ein enum-Datentyp probiere.

    enum material {Holz, Metall, keine};
    
    int main() {
    
    string Drehteil_Material = "Metall";
    
    material Drehteil;
    Drehteil = Metall;
    
    system("pause");
    }		
    

    Ist es möglich zu überprüfen ob der Wert der Variablen Drehteil_Material im enum vorliegt, da den Enumeinträgen ja Integer-Werte zugewiesen werden?

    Vielen Dank !!



  • @simpie sagte in String-Variable in Enum-Datentyp vorhanden?:

    Ist es möglich zu überprüfen ob der Wert der Variablen Drehteil_Material im enum vorliegt

    Direkt nicht, da die enum-member nach dem Kompilieren namentlich nicht mehr existieren aber zB über eine map:

    #include <iostream>
    #include <string>
    #include <map>
    
    enum material { Holz, Metall, keine };
    
    int main()
    {
    	std::map< std::string, material >material_map{
    		{ "Holz", Holz },
    		{ "Metall", Metall },
    		{ "keine", keine }
    	};
    
    	std::string Drehteil_Material{ "Metall" };
    
    	material Drehteil{ material_map[Drehteil_Material] };
    }
    


  • @swordfish sagte in String-Variable in Enum-Datentyp vorhanden?:

    material_map[Drehteil_Material]

    Mit operator [] wäre ich bei maps vorsichtig. Das fügt nämlich den Key hinzu, sofern er nicht vorhanden ist. Ist zwar ein wenig mehr Aufwand, aber ein find würde sich hier definitiv besser eignen.

    EDIT:

    Wenn die Liste zur Compile Time schon fest steht, würde ich auf folgendes zurück greifen. Ist zwar vll ein wenig verwirrend, aber das meiste davon ist template Code, der sich für solche Fälle recyclen lässt. Mit freundlicher Unterstützung von C++17 😉

    #include <array>
    #include <string>
    #include <string_view>
    #include <optional>
    #include <algorithm>
    
    namespace details {
      template<class> struct is_ref_wrapper : std::false_type {};
      template<class T> struct is_ref_wrapper<std::reference_wrapper<T>> : std::true_type {};
     
      template<class T>
      using not_ref_wrapper = std::negation<is_ref_wrapper<std::decay_t<T>>>;
     
      template <class D, class...> struct return_type_helper { using type = D; };
      template <class... Types>
      struct return_type_helper<void, Types...> : std::common_type<Types...> {
          static_assert(std::conjunction_v<not_ref_wrapper<Types>...>,
                        "Types cannot contain reference_wrappers when D is void");
      };
     
      template <class D, class... Types>
      using return_type = std::array<typename return_type_helper<D, Types...>::type,
                                     sizeof...(Types)>;
    }
     
    template < class D = void, class... Types>
    constexpr details::return_type<D, Types...> make_array(Types&&... t) {
      return {std::forward<Types>(t)... };
    }
    
    template <class Array>
    using LookupArrayFirst = typename Array::value_type::first_type;
    template <class Array>
    using LookupArraySecond = typename Array::value_type::second_type;
    
    template <class Array>
    std::optional<LookupArrayFirst<Array>> find(const Array& arr, LookupArraySecond<Array> key)
    {
        if (auto itr = std::find_if(std::begin(arr), std::end(arr),
            [&key](const auto& pair) { return pair.second == key; });
            itr != std::end(arr)
        )
        {
            return itr->first;
        }
        return std::nullopt;
    }
    
    template <class Array>
    std::optional<LookupArraySecond<Array>> find(const Array& arr, LookupArrayFirst<Array> key)
    {
        if (auto itr = std::find_if(std::begin(arr), std::end(arr),
            [&key](const auto& pair) { return pair.first == key; });
            itr != std::end(arr)
        )
        {
            return itr->second;
        }
        return std::nullopt;
    }
    
    
    // Ab hier beginnt dann der wirkliche Anwendungsfall
    enum Material
    {
        keine,
        holz,
        metall
    };
    
    using MaterialPair = std::pair<std::string_view, Material>;
    
    inline constexpr auto MaterialLookup{ make_array(
            MaterialPair("keine", Material::keine),
            MaterialPair("Holz", Material::holz),
            MaterialPair("Metall", Material::metall)
        )
    };
    
    int main()
    {
        std::string Drehteil_Material{ "Metall" };
    
        auto drehteil(find(MaterialLookup, Drehteil_Material));
    }
    

    Natürlich ist drehteil nun ein optional; man kann auch statt optional die reelle value zurück geben und im Fehlerfall eine exception schmeißen, ganz nach Lust und Laune.

    Dieses make_array Konstrukt habe ich mir mal fix hier ausgeborgt, lässt sich im Notfall aber auch einfach eliminieren.
    https://en.cppreference.com/w/cpp/experimental/make_array



  • Hallo

    vielen Dank für eure Antworten. Ich bin schon ein gutes Stück weiter gekommen 🙂



  • Mit better-enum wäre das leicht zu lösen:

    https://github.com/aantron/better-enums


Log in to reply