如何防止 C++ 的实例化当满足特定条件时模板类方法?

发布于 2024-10-04 23:54:21 字数 837 浏览 5 评论 0原文

我目前正在编写一个具有以下签名的通用向量模板类(几何实体,而不是容器)......


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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

初熏 2024-10-11 23:54:21

错误消息的最接近原因是,根据 文档< /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_cnop。但我猜你至少已经尝试过前者。 :)

现在我明白为什么这不起作用了。根据标准 14.7.1/1:

除非类模板
专业化已经明确
实例化(14.7.2)或显式
专门化(14.7.3),类
模板特化是隐式的
当专业化时实例化
在上下文中引用
需要一个完全定义的对象
类型或当完整性
类类型影响语义
程序。隐含的
类模板的实例化
专业化导致隐含的
声明的实例化,但是
不属于定义或默认值
类成员的参数
函数、成员类、静态数据
成员和成员模板;

因此,任何导致类被实例化的事情都会尝试实例化所有方法的声明,当 N != 3 时,这将失败。因此,您似乎需要使用始终存在的方法来将其交给函数模板。别担心,任何像样的编译器仍然能够通过此内联:

template< typename T, unsigned N > class vector;   // Fwd decl.

template< typename T, unsigned N >
inline boost::enable_if_c< (N == 3), vector<T, N> >::type
magic(const vector<T, N>& lhs, const vector<T, N>& rhs) {
    /* Do the calculation as before... */
    return ret;
}

template< typename T, unsigned N >
class vector {
    ...
    inline vector operator ^(const vector &rhs) const {
        return magic(*this, rhs);
    }
};

这将起作用,因为成员函数定义不会被实例化,除非它们被实际调用(或者它们的地址被获取等)。

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 named type whenever the first parameter (the condition) is true." That's clearly not satisfied here (unless your vector type just happens to contain typedef 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 was typename foo<T>::bar, and the bar type is not defined for all types T). vector (which here means vector<T, N>) will always be defined.

So definitely try getting rid of lazy_, or alternatively create a do-nothing traits class template <typename T> struct nop { typedef T type; }; and replace the 2nd arg to lazy_enable_if_c with nop<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:

Unless a class template
specialization has been explicitly
instantiated (14.7.2) or explicitly
specialized (14.7.3), the class
template specialization is implicitly
instantiated when the specialization
is referenced in a context that
requires a completely-defined object
type or when the completeness of the
class type affects the semantics of
the program. The implicit
instantiation of a class template
specialization causes the implicit
instantiation of the declarations, but
not of the definitions or default
arguments, of the class member
functions, member classes, static data
members and member templates;

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:

template< typename T, unsigned N > class vector;   // Fwd decl.

template< typename T, unsigned N >
inline boost::enable_if_c< (N == 3), vector<T, N> >::type
magic(const vector<T, N>& lhs, const vector<T, N>& rhs) {
    /* Do the calculation as before... */
    return ret;
}

template< typename T, unsigned N >
class vector {
    ...
    inline vector operator ^(const vector &rhs) const {
        return magic(*this, rhs);
    }
};

This will work because the member function definitions are not instantiated unless they are actually called (or their addresses are taken etc.).

兔小萌 2024-10-11 23:54:21

我相信你的问题是“位于类定义内”。我认为如果通过函数而不是方法重载运算符,麻烦会更少。

我认为一旦你切换到一个函数,也可能只需要简单的旧专业化而不是增强魔法,但我对此不太确定。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文