使用is作为模板类型参数时,我可以访问类字段吗?

时间:2015-11-17 09:29:18

标签: c++ templates

我知道这段代码看起来很奇怪,但我想知道是否有任何办法可以让它编译。<​​/ p>

template<typename T>
class A
{
public:
    enum
    {
        template_class_id = T::class_id
    };
};

class B : public A<B>
{
public:
    enum
    {
        class_id = 0x1234
    };
};

我得到了这样的错误:

clang++ test.cpp                                            
test.cpp:7:32: error: no member named 'class_id' in 'B'
        template_class_id = T::class_id
                            ~~~^
test.cpp:11:18: note: in instantiation of template class 'A<B>' requested here
class B : public A<B>
                 ^
1 error generated.

2 个答案:

答案 0 :(得分:5)

实例化基类B时,

A<B>是一个不完整的类型,因此B::class_id不存在。

要获得所需内容,您需要延迟template_class_id成员的实例化。

一种可能性是使template_class_id成为C ++ 14成员变量模板:

template<typename T>
class A
{
public:
    template <typename U=T>
    static constexpr int template_class_id = U::class_id;
};

class B : public A<B>
{
public:
    static constexpr int class_id = 0x1234;
};

Live Demo

不幸的是,这意味着您需要将template_class_id称为template_class_id<>,但它不需要任何额外类型。

另一种选择是依靠特质类:

template <typename T> struct ClassId;

template<typename T>
class A {
public:
    static constexpr int template_class_id = ClassId<T>::value;
};

class B;
template <> struct ClassId<B> {
    static constexpr int value = 0x1234;   
};

class B : public A<B> {
};

Live Demo

我认为这非常灵活,不需要您切换到功能。它确实意味着id在词汇上超出了你的类定义,但我认为这不是一个大问题。

答案 1 :(得分:3)

问题是class B : public A<B>。在您实例化A<B>时,B是不完整的类型,因此您无法使用B::class_id

以下方法可行:

template<typename T>
class A
{
public:
    static constexpr int get_template_class_id() { return T::get_class_id(); }
};

class B : public A<B>
{
public:
    static constexpr int get_class_id() { return 0x1234; }
};

这是因为成员函数在使用之前不会被实例化,并且此时B将不再是不完整的。