如何使用C ++模板创建具有任意数量案例的switch语句生成器?

时间:2014-12-18 20:53:39

标签: c++ templates

切换语句可能很长,所以我写了下面的类(在main()中有示例用法):

#include <iostream>
using namespace std;

template <typename In, typename Out, In In1, Out Out1, In In2, Out Out2, Out DefaultOut>
struct SwitchMap
{
    Out operator[](const In& input) const
    {
        switch (input) {
        case In1: return Out1;
        case In2: return Out2;
        default: return DefaultOut;
        }
    }
};

int main(int, char **)
{
    SwitchMap<unsigned int, unsigned int, 3, 1, 4, 2, 3> myMap;

    cout << myMap[3] << endl; // prints 1
    cout << myMap[4] << endl; // prints 2
    cout << myMap[5] << endl; // prints 3

    return 0;
}

我想实现两个目标: 1.我想让SwitchMap接受任意数量的情况(其中Outs的数量大于Ins的数量,以提供默认的返回值)。我的示例仅适用于两个Ins,两个Out和一个默认Out。 2.是否可以使map的声明看起来像这样:SwitchMap<3, 1, 4, 2, 3> myMap;?如果类型可以自动推断出来会很棒(虽然我意识到这可能会导致编译器选择int而不是unsigned int,我愿意处理它。

我可以实现其中一个或两个目标吗?

2 个答案:

答案 0 :(得分:0)

以下是使用if语句的示例。请注意,良好的编译器将生成与交换机一样高效的代码。结果也是constexpr。

#include <iostream>

template <typename T, T DEF>
inline constexpr T SwitchMap_helper(T) {
    return DEF;
}

template <typename T, T IN, T OUT, T... REST>
inline constexpr T SwitchMap_helper(T v) {
    return v == IN ? OUT : SwitchMap_helper<T, REST...>(v);
}

template <typename T, T... CASES>
struct SwitchMap {
    constexpr T operator[](T v) {
        return SwitchMap_helper<T, CASES...>(v);
    }
};

int
main() {

    SwitchMap<int, 1, 2, 3, 4, 5> sm1;
    std::cout << sm1[1] << std::endl;
    std::cout << sm1[3] << std::endl;
    std::cout << sm1[10] << std::endl;
}

答案 1 :(得分:0)

这是一个使用函数模板间接的小解决方法:

#include<tuple>
#include<iostream>

template<typename ... Args>
struct SwitchMap
{
    static const size_t ArgsSize = sizeof ... (Args); 
    using ArgsTuple = std::tuple<Args ...>;
    using InType = typename std::tuple_element<0,ArgsTuple>::type;
    using OutType = typename std::tuple_element<1,ArgsTuple>::type;

    std::tuple<Args ...> t;
    SwitchMap(Args const& ... args) : t(std::make_tuple(args ...))
    {
        static_assert((ArgsSize & 1) &&  (ArgsSize > 2), " ");
        //here possibly add another check for the consistency of the input types
    }

    template<int> struct int2type{};

    template<int N>
    OutType get(InType const& in, int2type<N>) const
    {
        return in == std::get<N>(t) ? std::get<N+1>(t) : get(in,int2type<N+2>());
    }

    OutType get(InType const& in, int2type<ArgsSize-1>) const
    {
        return std::get<ArgsSize-1>(t);
    }

    OutType operator[](InType const& in) const
    {
        return get(in,int2type<0>());
    }

};


template<typename ... Args>
auto makeSwitchMap(Args const& ... args)
{
    return SwitchMap<Args ...>(args ...);    
}

通过

进行调用
int main()
{
    auto switchMap = makeSwitchMap(1,std::string("Say Hi"),2,std::string("Say Goodbye"),std::string("Say nothing"));
    std::cout<<switchMap[1]<<std::endl;
    std::cout<<switchMap[2]<<std::endl;
    std::cout<<switchMap[4]<<std::endl;
}

产生

Say Hi
Say Goodbye
Say nothing

DEMO