成员声明中的模板 class 类型别名替换失败
Template class type alias failing substitution in member declaration
假设您有一个像这样的模板 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]) {}
但未使用 class
中定义的 length_t
类型别名。
如何让第一个定义发挥作用,从而使 class
的特性(如类型别名)的使用在其声明和定义中保持一致,或者第二个定义是唯一的解决方案在吗?
How does one get the first definition to work so as to keep the use of the class's features (like type aliases) consistent across its declaration & definitions,
我不得不承认我不明白这个错误,我不知道如何仅通过更改定义来修复它。错误信息相当混乱(你应该把它包括在问题中)。
... or is the second definition the only solution here?
不,不是。如果您不介意 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]) {}
length
是一个“模板特征”(不确定这个术语是否真的存在)。而不是将 length_t
作为 Object
的成员,您需要为 length<Object>
提供专门化(并且需要 Object
的前向声明)。 int
基本情况仅用于说明。如果你愿意,你仍然可以添加一个成员到 Object
到别名 length_t<Object>
.
我认为这是一个编译器错误,或者更进一步,是标准中的一个缺陷。
你的代码实际上没有问题,并且被MSVC接受。如果将定义放在 class 中,编译器将不会认为它是 ill-formed.
我发了一个 that is similar to this. and I get the result that, CWG2,不知道什么时候发的老问题,还在起草,意思是匹配规则out-of-definition 甚至 未指定 。这些奇怪的不匹配是因为编译器的不同实现。
然后,如何避免这个问题,首先你可以把定义放在class里面。如果它依赖于 class 定义后面定义的东西并且不能在里面定义,你可以:
- 让它独立:让
using length_t = unsigned int;
在外面。
- 声明时使其可推导:编译器可能不知道
typename Object<type>::length_t
和length_t
(在class内)是否是同一类型,尽管 typename Object<type>::length_t
不需要被推导。因为在声明时,编译器无法确保是否指定了 Object<type>
并使 length_t
不匹配,在我看来。正如@idclev 463035818 所说,template<...> using length_t = unsigned int;
将使编译器更容易匹配此定义。
假设您有一个像这样的模板 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]) {}
但未使用
class
中定义的length_t
类型别名。
如何让第一个定义发挥作用,从而使 class
的特性(如类型别名)的使用在其声明和定义中保持一致,或者第二个定义是唯一的解决方案在吗?
How does one get the first definition to work so as to keep the use of the class's features (like type aliases) consistent across its declaration & definitions,
我不得不承认我不明白这个错误,我不知道如何仅通过更改定义来修复它。错误信息相当混乱(你应该把它包括在问题中)。
... or is the second definition the only solution here?
不,不是。如果您不介意 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]) {}
length
是一个“模板特征”(不确定这个术语是否真的存在)。而不是将 length_t
作为 Object
的成员,您需要为 length<Object>
提供专门化(并且需要 Object
的前向声明)。 int
基本情况仅用于说明。如果你愿意,你仍然可以添加一个成员到 Object
到别名 length_t<Object>
.
我认为这是一个编译器错误,或者更进一步,是标准中的一个缺陷。
你的代码实际上没有问题,并且被MSVC接受。如果将定义放在 class 中,编译器将不会认为它是 ill-formed.
我发了一个
然后,如何避免这个问题,首先你可以把定义放在class里面。如果它依赖于 class 定义后面定义的东西并且不能在里面定义,你可以:
- 让它独立:让
using length_t = unsigned int;
在外面。 - 声明时使其可推导:编译器可能不知道
typename Object<type>::length_t
和length_t
(在class内)是否是同一类型,尽管typename Object<type>::length_t
不需要被推导。因为在声明时,编译器无法确保是否指定了Object<type>
并使length_t
不匹配,在我看来。正如@idclev 463035818 所说,template<...> using length_t = unsigned int;
将使编译器更容易匹配此定义。