假设您有一个模板化的class
,如下所示:
template <typename type>
class Object {
using length_t = unsigned int;
template <length_t length>
void put(type (&)[length]);
};
并且您在其中像这样声明了一个put(...)
方法。如何在class
之外声明put(...)
方法?
有人可能会采取一种方法:
/* ERROR: Doesn't match any declarations(?) */ template <typename type> template <typename Object<type>::length_t length> void Object<type>::put(type (&)[length]) {}
但这会导致一个特殊的错误
error: no declaration matches 'void Object<type>::put(type (&)[length])' note: candidate is: template <class type> template <unsigned int length> void Object<type>::put(type (&)[length])
以下是另一种声明
put(...)
方法以使其工作的方法:/* SUCCESS: But `length_t` alias isn't used */ template <typename type> template <unsigned int length> void Object<type>::put(type (&)[length]) {}
但是没有使用在CCD_ 7中定义的CCD_。
如何使第一个定义工作,以便在声明中保持class
的特性(如类型别名(的使用一致性&定义,还是第二个定义是这里唯一的解决方案?
如何让第一个定义工作,以便在其声明中保持类的特性(如类型别名(的使用一致&定义,
我不得不承认,我不理解这个错误,也不知道如何仅通过更改定义来修复它。错误消息相当令人困惑(您应该将其包含在问题中(。
。。。还是第二个定义是这里唯一的解决方案?
不,不是。如果你同意length_t
不作为会员,那么这可能会为你指明正确的方向:
template <template<typename> typename T>
struct length { using type = int; };
template <template<typename> typename T>
using length_t = typename length<T>::type;
template <typename> struct Object;
template <> struct length<Object> { using type = unsigned int; };
template <typename type>
class Object {
//using length_t = unsigned int;
template <length_t<Object> length>
void put(type (&)[length]);
};
template <typename type>
template <length_t<Object> length>
void Object<type>::put(type (&)[length]) {}
CCD_;模板特征";(不确定这个术语是否真的存在(。您不需要将length_t
作为Object
的成员,而需要为length<Object>
提供专门化(这需要Object
的前向声明(。int
基本情况仅用于说明。如果您愿意,您仍然可以将Object
的成员添加到别名length_t<Object>
。
实时演示
我认为这是一个编译器错误,或者更进一步,是标准中的缺陷。
您的代码实际上没有问题,并且被MSVC接受。如果你把定义放在类中,没有编译器会认为它格式不正确。
我发布了一个与此类似的问题。我得到的结果是,CWG2,这个发布时无人知晓的古老问题,仍然是起草,这意味着定义外的匹配规则甚至是unspecified。这些奇怪的不匹配是因为编译器的实现不同。
然后,为了避免这个问题,首先可以将定义放在类中。如果它依赖于类定义后面定义的东西,而不能在内部定义,则可以:
-
使其独立:让
using length_t = unsigned int;
在外面 -
在声明时使其可推导:编译器可能不知道
typename Object<type>::length_t
和length_t
(在类内(是否是同一类型,尽管typename Object<type>::length_t
不需要是可推导的。因为在声明的时候,编译器不能确保Object<type>
是否被指定,并且使length_t
不匹配,在我看来。正如@idclev 463035818所说,template<...> using length_t = unsigned int;
将使编译器更容易匹配这个定义