避免在字符串中进行if-else分支以进行类型调度 [英] Avoid if-else branching in string to type dispatching

查看:80
本文介绍了避免在字符串中进行if-else分支以进行类型调度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,当您编写一个接受参数的CLI工具时,必须对其进行处理。大多数情况下,您希望根据参数的值在行为之间进行切换。

Usually when you write a CLI tool which accepts parameter you have to deal with them. Most of the time you want to switch between behaviours based on the value of an argument.

以下是一个常见的用例,其中程序接受一个类型然后打印基于这种类型的东西。我正在使用Boost进行预处理并自动生成整个 if-else 分支。
就可维护性而言,这非常好,因为当我引入新类型时,我只需要更新 define 。另一方面,它远非现代而优雅。

The following is a common use case, where the program accepts a type and then prints something based on that type. I am using Boost to pre-process and auto generate the whole if-else branches. This is very nice in terms of maintainability as I only need to update a define when I introduce a new type. On the other hand it is quite far from being modern and elegant.

我考虑过使用更好的枚举来避免使用 if-else 使用 _from_string 实用程序功能。但是,从枚举转换为类型的方法对我来说还是很模糊。

I thought about using better-enums to avoid using the if-else to convert from string into an enum using the _from_string utility function. But then the way to go from enum to a type is still obscure to me.

关于如何保持当前实现的良好可维护性但避免使用pre的任何建议处理器和宏功能?

Any suggestion on how to keep the nice maintainability of the current implementation but avoid to use pre-processor and macro functionalities?

#include <iostream>
#include <cstdlib>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <type_traits>
using a_type = int;
using b_type = long;
using c_type = float;
using d_type = double;

#define TYPES (a)(b)(c)(d)

template<typename T>
void foo(){
    T num = 1;
    std::cout << typeid(decltype(num)).name() << " : "<< num << std::endl;
};

int main(int argc, char **argv)
{
if (argc < 1) {
    return 1;
}
std::string type = argv[1];

    if (false) {
#define LOOP_BODY(R, DATA, T)                  \
    }                                          \
    else if (type == BOOST_PP_STRINGIZE(T)) {  \
        foo<BOOST_PP_CAT(T, _type)>();         \

        BOOST_PP_SEQ_FOR_EACH(LOOP_BODY, _, TYPES);
#undef LOOP_BODY
    } else {
        std::cout << "ERROR: Unknown type " << type << std::endl;
    }

}

https://wandbox.org/permlink/60bAwoqYxzU1EUdw

推荐答案

另一种方法是使用纯数组和 std :: find_if 代替 if-else

Another way is to use a plain array and std::find_if instead of if-else:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <typeinfo>

struct Handler {
    char const* name;
    void(*fn)(std::string const&); // Or std::function<> to accept lambdas.
};

struct A {};
struct B {};

template<class T>
void foo(std::string const& name) {
    std::cout << "foo<" << typeid(T).name() << ">: " << name << '\n';
}

int main(int, char** av) {
    Handler const handlers[] = {
          {"a", foo<A>}
        , {"b", foo<B>}
    };
    std::string const name = av[1];
    auto handler = std::find_if(std::begin(handlers), std::end(handlers), [&name](auto const& h) {
        return name == h.name;
    });
    if(handler != std::end(handlers))
        handler->fn(name);
}

这篇关于避免在字符串中进行if-else分支以进行类型调度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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