c++ - 模板二元运算符重载决议

标签 c++ templates

我在使用 Apple LLVM 编译器(XCode 4.5.2 附带)时遇到问题,同时使用 GCC 正确运行。比关于编译器问题的争论更重要(尽管我认为 GCC 是正确的),这提出了关于重载运算符时模板特化的解析顺序的问题 [1]。

考虑一个简单的矩阵类 template <class T> class matrix_t ,具有定义乘法结果类型的特征(使用标量、矩阵或 vector )。这类似于以下代码:

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>();
  }

};

还考虑 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;
}

“有问题的线路”运行全局定义的 operator*(matrix_t<T> const&, vectorN<U, N> const&)在 GCC 和 template <class U> matrix_t<T>::operator*(U const&) const 上在 LLVM 上。所以它就像 matrix_t<T>::operator*(U const&)正在捕获所有模板特化查找。一个简单的“修复”是移动全局 operator*进入矩阵类。

我首先认为这是特征类中的问题,它可能太复杂或错误 (SFINAE)。但即使简化特征或完全禁用它(如在粘贴代码中)也会产生错误。然后我认为这是一个顺序问题(就像 Herb Shutter 的文章中那样),但是移动了全局 operator*matrix_t 之间声明和定义不会改变任何东西。

问题来了

当然,真正的问题是template <class U> matrix_t::operator*(U const&) const太笼统了,但是:

  • 标准是否涵盖此类问题?
  • 类内部定义的运算符重载是否优先于全局定义的运算符重载?
  • (更像是一个词汇问题)operator*(matrix_t<T> const&, vectorN<U, N> const&) 的资格是什么? ?模板重载运算符特化?这更多是模板特化还是重载函数?它的基本定义是什么?由于它本质上是一个重载运算符,所以我有点迷茫。

[1] 我已阅读 Herb Shutter 关于模板特化顺序的建议。

最佳答案

does an operator overload defined inside a class have priority over an operator overload defined globally?

。根据 C++11 标准的第 13.3.1/2 段:

The set of candidate functions can contain both member and non-member functions to be resolved against the same argument list. So that argument and parameter lists are comparable within this heterogeneous set, a member function is considered to have an extra parameter, called the implicit object parameter, which represents the object for which the member function has been called. For the purposes of overload resolution, both static and non-static member functions have an implicit object parameter, but constructors do not.

此外,标准成员函数中没有任何地方提到优先于非成员函数,反之亦然。

is this kind of problem something covered by the standard?

是的。选择全局运算符(应该!)的原因是它是一个比类中定义的函数模板更专业的模板:在模板参数推导之后,两者vectorN<U, N> const&matrix_t<T> const&可以匹配 matrix_t<T> const& r , 但前者比后者更专业,因此是首选。

根据第 13.3.3/1 段:

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then:

[...]

F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.

因此:

So it is like the matrix_t::operator*(U const&) is catching all template specialization lookups

此行为属于错误。但是,请注意,这些不是特化,而是重载

最后:

what is the qualification of operator * (matrix_t<T> const&, vectorN<U, N> const&)?

我想您可以说它是一个(全局)运算符重载模板。它不是特化,因为模板函数特化有不同的语法。因此,没有它专门化的主模板。它只是一个函数模板,一旦实例化,就会生成乘法运算符的重载

关于c++ - 模板二元运算符重载决议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15028835/

相关文章:

c++ - MongoDB 2.4 C++ 驱动程序 - 对 `SSL_CTX_use_certificate_chain_file' 的 undefined reference

c++ - 模板化函数只接受右值

C++ 模板机制

templates - 如何从已解析的模板中获取模板 'actions' 的 map 或列表?

c++ - 如何修复此类模板

c++ - 模板 C++ 类声明中的类型/值不匹配

c++ - 可变参数模板查询

c++ - 简单的内核编译问题

c++ - 无法在 lambda 中捕获

c++ - Qt - 具有自定义参数的可重用绘图函数