如何防止 C++ 的实例化当满足特定条件时模板类方法?
我目前正在编写一个具有以下签名的通用向量模板类(几何实体,而不是容器)......
template< typename T, unsigned N >
class vector
{...}
其中 T 是算术类型,N 是维度。我想将叉积定义为运算符 ^ 的重载(位于类定义内部),并仅在 N == 3 时启用它。我现在拥有的是:
typename boost::lazy_enable_if_c< (N == 3), vector >::type
inline operator ^(const vector &rhs) const
{
vector ret;
ret(0) = val_[1] * rhs(2) - val_[2] * rhs(1);
ret(1) = val_[2] * rhs(0) - val_[0] * rhs(2);
ret(2) = val_[0] * rhs(1) - val_[1] * rhs(0);
return ret;
}
不幸的是,用 N != 3 实例化此模板,甚至尽管未引用运算符 ^,但会产生以下错误:
error: no type named ‘type’ in ‘struct boost::lazy_enable_if_c < false, flare::math::vector < flare::math::fixed < short int, 8u >, 2u > >’
我做错了什么?在这种情况下是否有 boost::enable_if 的替代方案?
非常感谢。
I'm currently writing a generic vector template class (the geometric entity, not the container) with the following signature...
template< typename T, unsigned N >
class vector
{...}
... where T is an arithmetic type and N, the dimension. I would like to define the cross product as an overload of operator ^ (located inside class definition) and enable it only when N == 3. What I've have now is:
typename boost::lazy_enable_if_c< (N == 3), vector >::type
inline operator ^(const vector &rhs) const
{
vector ret;
ret(0) = val_[1] * rhs(2) - val_[2] * rhs(1);
ret(1) = val_[2] * rhs(0) - val_[0] * rhs(2);
ret(2) = val_[0] * rhs(1) - val_[1] * rhs(0);
return ret;
}
Unfortunately, instantiating this template with N != 3, even though operator ^ isn't referenced, yields the following error:
error: no type named ‘type’ in ‘struct boost::lazy_enable_if_c < false, flare::math::vector < flare::math::fixed < short int, 8u >, 2u > >’
What am I doing wrong? Is there an alternative to boost::enable_if in such case?
Thank you very much.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
错误消息的最接近原因是,根据 文档< /a>, “当第一个参数(条件)为 true 时,
lazy_enable_if
的第二个参数必须是定义名为type
的嵌套类型的类类型。”这显然不满足于此(除非您的vector
类型恰好包含typedef some type;
)。这里不需要
lazy_...
。根据文档,仅当第二个参数未定义时才需要(例如,如果第二个参数是typename foo::bar
,并且bar
类型是没有为所有类型T
定义)。vector
(这里的意思是vector
)将始终被定义。因此,一定要尝试摆脱
lazy_
,或者创建一个不做任何事的特征类template; struct nop { typedef T 类型; };
并将第二个参数替换为lazy_enable_if_c
为nop
。但我猜你至少已经尝试过前者。 :)现在我明白为什么这不起作用了。根据标准 14.7.1/1:
因此,任何导致类被实例化的事情都会尝试实例化所有方法的声明,当
N != 3
时,这将失败。因此,您似乎需要使用始终存在的方法来将其交给函数模板。别担心,任何像样的编译器仍然能够通过此内联:这将起作用,因为成员函数定义不会被实例化,除非它们被实际调用(或者它们的地址被获取等)。
The proximal cause of the error message is that, according to the docs, "The second argument of
lazy_enable_if
must be a class type that defines a nested type namedtype
whenever the first parameter (the condition) is true." That's clearly not satisfied here (unless yourvector
type just happens to containtypedef something type;
).You don't need
lazy_...
here. According to the docs, that's only needed if the 2nd arg could be undefined (e.g. if the 2nd arg wastypename foo<T>::bar
, and thebar
type is not defined for all typesT
).vector
(which here meansvector<T, N>
) will always be defined.So definitely try getting rid of
lazy_
, or alternatively create a do-nothing traits classtemplate <typename T> struct nop { typedef T type; };
and replace the 2nd arg tolazy_enable_if_c
withnop<vector>
. But my guess is you've already tried the former at least. :)And now I see why that won't work. According to the standard 14.7.1/1:
So anything that causes the class to be instantiated will try to instantiate declarations for all methods, which will fail when
N != 3
. So it looks like you'll need to use an always-present method that hands off to a function template instead. Don't worry, any decent compiler will still be able to inline through this:This will work because the member function definitions are not instantiated unless they are actually called (or their addresses are taken etc.).
我相信你的问题是“位于类定义内”。我认为如果通过函数而不是方法重载运算符,麻烦会更少。
我认为一旦你切换到一个函数,也可能只需要简单的旧专业化而不是增强魔法,但我对此不太确定。
I believe your problem is "located inside class definition". I think you'd have less trouble if you overload the operator via a function rather than via a method.
I think it may also be possible to get by with just plain old specialization rather than boost magic once you switch to a function, but I'm less sure about that.