我知道这段代码看起来很奇怪,但我想知道是否有任何办法可以让它编译。</ 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.
答案 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;
};
不幸的是,这意味着您需要将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> {
};
我认为这非常灵活,不需要您切换到功能。它确实意味着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
将不再是不完整的。