[英]Template binary operator overload resolution
在与GCC一起正确运行时,我使用Apple LLVM编译器(与XCode 4.5.2一起提供)遇到了问题。 比就编译器问题进行辩论(更重要的是,我认为GCC是正确的)更重要,这引起了有关重载运算符时模板专业化的解析顺序的问题[1]。
考虑一个简单的矩阵类template <class T> class matrix_t
,其特征定义相乘的结果类型(标量,矩阵或向量)。 这将类似于以下代码:
template <class T, class U, class Enable = void>
struct matrix_multiplication_traits {
//typedef typename boost::numeric::conversion_traits<T,U>::supertype type;
typedef double type;
};
template <class T, int N>
struct vectorN {
std::vector<T> vect;
vectorN() : vect(N) { for(int i = 0; i < N; i++) vect[i] = i; }
};
template <class T>
class matrix_t {
std::vector<T> vec;
public:
matrix_t<T> operator*(matrix_t<T> const& r) const {
std::cout << "this_type operator*(this_type const& r) const" << std::endl;
return r;
}
template <class U>
matrix_t<typename matrix_multiplication_traits<T, U>::type>
operator*(U const &u) const {
std::cout << "different_type operator*(U const &u) const" << std::endl;
return matrix_t<typename matrix_multiplication_traits<T, U>::type>();
}
};
还考虑vectorN
的operator*
的vectorN
:
template <class T, class U, int N>
//vectorN<typename matrix_multiplication_traits<T,U>::type, N>
vectorN<double, N>
operator*(matrix_t<T> const&m, vectorN<U, N> const&v)
{
std::cout << "vectorN operator*(matrix, vectorN)" << std::endl;
//return vectorN<typename matrix_multiplication_traits<T,U>::type, N>();
return vectorN<double, N>();
}
并考虑一个简单的测试程序:
int main(int argc, const char * argv[])
{
matrix_t<double> test;
vectorN<double, 10> my_vector;
test * my_vector; // problematic line
return 0;
}
“问题线”在GCC上运行全局定义的operator*(matrix_t<T> const&, vectorN<U, N> const&)
,在LLVM上运行template <class U> matrix_t<T>::operator*(U const&) const
。 因此,就像matrix_t<T>::operator*(U const&)
正在捕获所有模板特化查询。 一个简单的“解决方案”就是将全局operator*
移到矩阵类中。
我首先认为这是特质课中的一个问题,可能太复杂或错误(SFINAE)。 但是,即使简化特征或完全禁用特征(如在粘贴代码中)也会产生错误。 然后,我认为这是一个顺序问题(就像在Herb Shutter的文章中一样),但是在matrix_t
声明和定义之间移动全局operator*
不会改变任何事情。
当然,真正的问题是template <class U> matrix_t::operator*(U const&) const
太笼统,但是:
operator*(matrix_t<T> const&, vectorN<U, N> const&)
的资格是什么? 模板重载运算符专业化? 这是模板专门化还是函数重载? 它的基本定义是什么? 由于它本质上是一个重载运算符,我有点迷茫。 [1]我已经阅读了有关模板专业化订单的Herb Shutter建议。
在类内定义的运算符重载是否优先于全局定义的运算符重载?
不行 根据C ++ 11标准的第13.3.1 / 2段:
候选函数集可以包含要针对同一参数列表解析的成员函数和非成员函数 。 为了使参数列表和参数列表在此异构集合中具有可比性,因此成员函数被认为具有一个额外的参数,称为隐式对象参数,该参数表示已为其调用成员函数的对象。 为了重载解析,静态和非静态成员函数均具有隐式对象参数,而构造函数则没有。
此外,在标准成员函数中,没有任何地方比非成员函数更受青睐,反之亦然。
标准涵盖了此类问题吗?
是。 选择( 应该是! )全局运算符的原因是,它是比类内部定义的函数模板更专业的模板:扣除模板参数后, vectorN<U, N> const&
和matrix_t<T> const&
都可以使之与matrix_t<T> const& r
匹配,但是前者比后者更专业,因此是首选。
根据第13.3.3 / 1段:
给定这些定义,如果对于所有自变量i,ICSi(F1)的转换顺序都不比ICSi(F2)差,则将一个可行函数F1定义为比另一个可行函数F2更好的函数,然后:
[...]
— F1和F2是功能模板专业化,根据14.5.6.2中描述的部分排序规则,F1的功能模板比F2的模板更专业。
因此:
因此,就像matrix_t :: operator *(U const&)正在捕获所有模板特化查询
此行为被视为错误 。 但是,请注意,这些不是专长 ,而是重载 。
最后:
operator * (matrix_t<T> const&, vectorN<U, N> const&)
的资格是什么?
我猜你可以说这是一个(全局)运算符重载模板。 这不是专业化,因为模板函数专业化具有不同的语法。 因此,没有主模板专门化。 只是一个函数模板,一旦实例化,就会生成乘法运算符的重载 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.