7

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


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 的方法?

非常感谢。

4

2 回答 2

5

错误消息的近端原因是,根据文档,“的第二个参数lazy_enable_if必须是定义嵌套类型的类类型,type只要第一个参数(条件)为真,就会命名。” 这显然不满足于此(除非您的vector类型恰好包含typedef something type;)。

你不需要lazy_...这里。根据文档,仅当第二个参数可能未定义时才需要这样做(例如,如果第二个参数是typename foo<T>::bar,并且bar没有为所有类型定义类型T)。 vector(这里的意思是vector<T, N>)将始终被定义。

因此,一定要尝试摆脱lazy_,或者创建一个无所事事的特征类template <typename T> struct nop { typedef T type; };并将第二个 arg 替换lazy_enable_if_cnop<vector>。但我猜你至少已经尝试过前者。:)

现在我明白为什么那行不通了。 根据标准 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);
    }
};

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

于 2010-11-28T11:37:57.203 回答
2

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

我认为一旦你切换到一个函数,也可能只使用普通的旧专业而不是增强魔法,但我不太确定这一点。

于 2010-11-28T06:30:08.093 回答