gpt4 book ai didi

c++ - 将用户输入转换为 C++ 类型的 if/else 语句过多

转载 作者:行者123 更新时间:2023-12-01 14:03:01 25 4
gpt4 key购买 nike

我有一个带有 3 个模板参数的模板类。

template <class T, class U, class Y>
class MyClass {};

我想通过 CLI 参数从用户那里获得输入,比如 ./cli float driver-x load
  • 第一个参数可以是 floatdouble
  • 第二个参数是驱动程序名称: driver-x , driver-y , ...
  • 第三个参数是关于 Action 类型的: load , unload , ...

  • 如果我想根据用户输入创建 MyClass 的新实例,我必须定义许多 if/else 语句。因为用户输入是 string,我必须为它们准备一个条件。
    所以,它会是这样的:
    if (data_type == "float")
    if (driver == "driver-x")
    if (action == "load")
    MyClass<float, DriverX, Load> t;
    t......

    据我所知,在 C++ 中不可能将类型存储在变量中。

    那么,有没有办法改进 if/else 语句?就像是:
    if (data_type == "float")
    //

    if (driver == "driver-x")
    //

    if (action == "load")
    //

    MyClass<......> t;
    t.....;

    还是有其他方式?

    我正在寻找一种方法来改进这些 if/else 语句。

    最佳答案

    您可以构建一些机制来为您执行此操作,将其提取到函数调用中。

    例如,在这里我构建了一个包含字符串和类型的元组,然后我根据所有这些字符串检查传递的字符串:

    #include <string_view>
    #include <cstddef>
    #include <tuple>
    #include <utility>
    #include <type_traits>

    template<class T>
    struct mapped_type {
    const std::string_view key;
    using type = T;

    explicit constexpr operator bool() const noexcept {
    return true;
    }
    };

    namespace detail {
    template<class K, class F, class M, std::size_t I>
    constexpr void lookup_impl(const K& key, F&& f, M&& m, std::integral_constant<std::size_t, I>) {
    using tuple_t = typename std::remove_cv<typename std::remove_reference<M>::type>::type;
    if constexpr (I < std::tuple_size<tuple_t>::value) {
    const auto& mapping = std::get<I>(m);
    if (mapping.key == key) {
    std::forward<F>(f)(mapping);
    return;
    }
    lookup_impl(key, std::forward<F>(f), std::forward<M>(m), std::integral_constant<std::size_t, I + 1>{});

    } else {
    std::forward<F>(f)(std::false_type{});
    }
    }
    }

    // Calls `f` with the first value from `m` that matches the key
    // or `std::false_type{}` if no key matches.
    template<class K, class F, class M>
    constexpr void lookup(const K& key, F&& f, M&& m) {
    detail::lookup_impl(key, std::forward<F>(f), std::forward<M>(m), std::integral_constant<std::size_t, 0>{});
    }

    // This is our mapping for the first argument
    inline constexpr auto data_type_map = std::make_tuple(
    mapped_type<float>{ "float" },
    mapped_type<double>{ "double" }
    );

    // Example usage
    #include <iostream>

    int main() {
    const char* s = "float";

    lookup(s, [](const auto& arg) {
    if constexpr (!arg) {
    std::cout << "Invalid type\n";
    } else {
    using type = typename std::remove_cv<typename std::remove_reference<decltype(arg)>::type>::type::type;
    std::cout << "Got type: " << typeid(type).name() << '\n';
    }
    }, data_type_map);
    }

    然后你可以在 lambda 中递归调用它。

    您还可以创建一个版本,该版本采用一组键和一组值来调用具有多个参数的函数:

    #include <string_view>
    #include <tuple>
    #include <utility>
    #include <type_traits>

    template<class T>
    struct mapped_type {
    const std::string_view key;
    using type = T;

    explicit constexpr operator bool() const noexcept {
    return true;
    }
    };

    namespace detail {
    template<class K, class F, class M, std::size_t I>
    constexpr void lookup_impl(F&& f, const K& key, M&& m, std::integral_constant<std::size_t, I>) {
    using tuple_t = typename std::remove_cv<typename std::remove_reference<M>::type>::type;
    if constexpr (I < std::tuple_size<tuple_t>::value) {
    const auto& mapping = std::get<I>(m);
    if (mapping.key == key) {
    std::forward<F>(f)(mapping);
    return;
    }
    lookup_impl(std::forward<F>(f), key, std::forward<M>(m), std::integral_constant<std::size_t, I + 1>{});
    } else {
    std::forward<F>(f)(std::false_type{});
    }
    }

    template<class F, class K, class M, std::size_t I>
    constexpr void multilookup_impl(F&& f, const K& keys, M&& mappings, std::integral_constant<std::size_t, I>) {
    constexpr std::size_t size = std::tuple_size<typename std::remove_cv<typename std::remove_reference<K>::type>::type>::value;
    if constexpr (I >= size) {
    std::forward<F>(f)();
    } else {
    lookup_impl([&](const auto& current_lookup) {
    multilookup_impl(
    [&](const auto&... args) { std::forward<F>(f)(current_lookup, args...); },
    keys, mappings, std::integral_constant<std::size_t, I + 1>{}
    );
    }, std::get<I>(keys), std::get<I>(mappings), std::integral_constant<std::size_t, 0>{});
    }
    }
    }

    template<class F, class K, class M>
    constexpr void lookup(F&& f, const K& keys, M&& mappings) {
    using map_tuple_t = typename std::remove_cv<typename std::remove_reference<M>::type>::type;
    using key_tuple_t = typename std::remove_cv<typename std::remove_reference<K>::type>::type;
    constexpr std::size_t size = std::tuple_size<key_tuple_t>::value;
    static_assert(size == std::tuple_size<map_tuple_t>::value, "Wrong number of keys for given number of maps");
    detail::multilookup_impl(std::forward<F>(f), keys, mappings, std::integral_constant<std::size_t, 0>{});
    }

    看起来几乎相同,但还有一层调用。

    它将像这样使用:

    #include <iostream>


    inline constexpr auto data_type_map = std::make_tuple(
    mapped_type<float>{ "float" },
    mapped_type<double>{ "double" }
    );

    inline constexpr auto driver_type_map = std::make_tuple(
    mapped_type<DriverX>{ "driver-x" },
    mapped_type<DriverY>{ "driver-y" }
    );

    inline constexpr auto action_type_map = std::make_tuple(
    mapped_type<Load>{ "load" },
    mapped_type<Unload>{ "unload" }
    );

    int main() {
    const char* a = "float";
    const char* b = "driver-x";
    const char* c = "load";

    lookup([](const auto& data, const auto& driver, const auto& action) {
    if constexpr (!data) {
    std::cout << "Could not parse data!\n";
    } else if constexpr (!driver) {
    std::cout << "Could not parse driver!\n";
    } else if constexpr (!action) {
    std::cout << "Could not parse action!\n";
    } else {
    using data_type = typename std::remove_cv<typename std::remove_reference<decltype(data)>::type>::type::type;
    using driver_type = typename std::remove_cv<typename std::remove_reference<decltype(driver)>::type>::type::type;
    using action_type = typename std::remove_cv<typename std::remove_reference<decltype(action)>::type>::type::type;

    MyClass<data_type, driver_type, action_type> t;
    std::cout << "Constructed a " << typeid(decltype(t)).name() << '\n';
    }
    },
    std::array<const char*, 3>{ a, b, c },
    std::forward_as_tuple(data_type_map, driver_type_map, action_type_map)
    );
    }

    关于c++ - 将用户输入转换为 C++ 类型的 if/else 语句过多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61309900/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com