11

当我尝试用 Clang 编译它时

template<class T>
struct Field
{
    char const *name;
    Field(char const *name) : name(name) { }
};

template<class Derived>
class CRTP { static Field<Derived> const _field; };

class Class : public CRTP<Class> { };
Field<Class>   const CRTP<Class>::_field("blah");

int main() { }

我明白了

error: template specialization requires 'template<>'
Field<Class>   const CRTP<Class>::_field("blah");
                     ~~~~~~~~~~~  ^

我根本不明白这个错误。我的定义有什么问题,我_field该如何解决?

(请注意,_field所有子类的参数不一定相同。)

4

3 回答 3

18

为了让编译器将此识别为模板特化(例如,能够检查语法),您需要以下template关键字:

template<>
Field<Class> const CRTP<Class>::_field("blah");

它的括号是空的,因为所有模板参数都是专用的,但你不能就这样离开它。

于 2013-03-30T21:55:10.147 回答
3

该错误准确地说明了缺少的内容。 template<>在该行之前丢失。

template<>
Field<Class> const CRTP<Class>::_field("blah");

但是请注意,Field<Class>如果您键入的 是唯一的,则可用于构造Field<Class>具有给定字符串的所有实例。

template<typename T>
struct field_trait;

template<class T>
struct Field
{
    char const *name;
    Field() : name(field_trait<T>::get_name()) {}
};

template<class Derived>
class CRTP { static Field<Derived> const _field; };
template<class Derived>
class CRTP<Derived>::_field;

class Class;

template<>
struct field_traits<Class> {
  static const char* get_name() { return "blah"; }
};

class Class : public CRTP<Class> { };

int main() { }

这意味着 的每个实例都Field<Class>始终具有名称"blah"

我会问的一个问题是,你真的需要存储来表示Field<Class>实际上有一个指向字符串的指针吗?如果需要,它是否需要是唯一的,如果需要,它是否需要“裸露”?因为找出static实例存在的位置有点烦人。

连同field_traits上面:

template<class Derived>
class CRTP { static Field<Derived>& field() const { static Field<Derived> _field( field_traits<Derived>::get_name()); return _field; };

这将“存储在哪里_field”的问题变成了编译器的问题。它由 的内容初始化field_traits<T>::get_name()

于 2013-03-30T21:58:01.027 回答
3

A static data member must have both a declaration and a definition. If this was a plain class it would look like this:

// header:
class C {
    static int i;
};

// source:
int C::i = 3;

Templates aren't ordinarily defined in source files, so the code would look something like this:

// header:
template <class T>
class C {
    static int i;
};

template <class T>
int C<T>::i = 3;

In your code, you don't have the definition of the static data member. That's okay if you don't use it. But the code that the compiler is complaining about defines a static data member for CRTP<Class>; that's a specialization (because it's not applicable to all instantiations of CRTP, just to this one), and the compiler is saying that you have to tell it that it's a specialization. So do as you're told:

template <>
Field<Class> const CRTP<Class>::_field("blah");

or, to write the non-specialized template version, use the usual template syntax:

template <class T>
Field<T> const CRTP<T>::_field("blah");
于 2013-03-30T21:58:12.743 回答