使用可变修改类型实例化模板

时间:2010-09-03 20:47:45

标签: c++ templates c++11

我的一个类'成员方法作为枚举类型的参数:它为不同的枚举产生不同的副作用。我想知道是否可以使用模板作为查找表,我想到了两种可能的解决方案,但它们似乎都不起作用:

//// 1 ////

class A {

    public:

    enum AEnum : uint8_t { first, second, ... };

    private:

    template<AEnum N, typename T>
    struct impl {
        static void do_sth(T t) { ... };
    };

    template<typename T>
    struct impl<first, T> {
        static void do_sth(T t) { ... };
    };

    public:


    template<typename T>
    void do_sth(AEnum e, T t) {
        impl<e, T>::do_sth(t);
    }

}

//// 2 ////

class A {

    public:

    enum AEnum : uint8_t { first, second, ... };

    private:

    template<typename T_enum, typename T>
    struct impl {
        static void do_sth(T t) { ... };
    };

    template<typename T>
    struct impl<uint8_t[2], T> { // A::first
        static void do_sth(T t) { ... };
    };

    public:


    template<typename T>
    void do_sth(AEnum e, T t) {
        impl<uint8_t[static_cast<uint8_t>(e) + 1u], T>::do_sth(t);
    }

}

以这种方式编码是不是很糟糕?

@Oli Charlesworth

  

switch语句出了什么问题?

do_sth的第二个参数(T)的支持类型随e的值而变化,例如A :: first支持积分,A ::第二个STL容器,例如:

    template<typename T>
    void do_sth(AEnum e, T t) {
        switch(e) {
            case first:
                std::cout << &t << std::endl;
                break;
            case second:
                std::cout << t.data() << std::endl;
                break;
            default:
                break;
    }

A a;
a.do_sth(A::first, 0);

2 个答案:

答案 0 :(得分:2)

你必须让AEnum arg成为do_sth的模板参数:


 template<AEnum e, typename T>
    void do_sth(T t) { ... }

...并将其称为a.do_sth<A::first>(0)

或者,您可以编写单独的函数(do_sth_integraldo_sth_container,...),或者,如果特定T只有一个正确的操作过程,则推导出“正确”的枚举使用元编程/重载技巧给定T的值。

例如,这是一种编写两个函数的方法,例如检测数字类型和容器类型:


//The extra dummy argument is invalid for types without a nested 
//"iterator" typedef
template<typename T>
void do_sth(T t, typename T::iterator * = 0)
{
    //container type code
}

//The dummy arg is invalid for types without a 
//std::numeric_limits specialization
template<typename T>
void do_sth(T t, 
typename boost::enable_if_c<std::numeric_limits<T>::is_specialized>::type * = 0) 
{
    //numeric type code
}

当然,如果您传递的是具有迭代器typedef和numeric_limits特化的T,或者两者都没有,则会失败。

如果特定T只有一个合理的动作,并且很难正确猜出哪个重载应该用于未知的T,那么你可以使用一个用户必须明确专门化的特征类,或者只需要用户专门研究“impl”或派遣类。

即使在程序运行时从未调用过代码路径,也无法编写类似3.data()之类的函数。编译器不知道它永远不会被调用,并且在任何情况下,它都会以导致诊断错误所需的方式违反语言的类型系统。

答案 1 :(得分:1)

是的,你编码的内容没有任何意义。模板实例化在编译器时解析,而e的值显然只在运行时知道。

switch语句出了什么问题?