【问题标题】:Should operators be declared as non-member non-template friends是否应该将运算符声明为非成员非模板朋友
【发布时间】:2015-07-27 17:09:24
【问题描述】:

考虑this question,这与以下代码未编译有关:

std::vector<int> a, b;
std::cout << (std::ref(a) < std::ref(b));

它无法编译,因为vector 的向量comparison operators 是非成员函数模板,并且不允许考虑隐式转换。但是,如果将运算符改为非成员非模板,friend 函数:

template <class T, class Allocator = std::allocator<T>>
class vector {
    // ...

    friend bool operator<(const vector& lhs, const vector& rhs) {
        // impl details
    }
};

那么这个版本的operator&lt; 会被 ADL 发现并被选为最佳可行的重载,并且原始示例会被编译。鉴于此,是否有理由更喜欢我们目前拥有的非成员函数模板,或者这是否应该被视为标准中的缺陷?

【问题讨论】:

  • operator&lt;&lt; 也有类似的问题,并且在一些地方流式传输:这确实带来了一些问题。我可以写一个template&lt;class C&gt; operator&lt;&lt;(std::basic_ostream&lt;C&gt;&amp;,std::basic_string&lt;C&gt;&amp;) without 取决于两个(任何一个)的前向声明。 “Koenig 操作员”至少需要其中一个(哪个?),它需要两者吗? (这是相切的,因为它是关于两种类型的运算符,而不是像上面那样)
  • 我不明白你为什么要写std::ref(a) &lt; std::ref(b)。对我来说这似乎有悖常理,因为 ref 返回一个完全独立的类类型。
  • @Columbo 它适用于ints。此外,我不知道你为什么会做很多事情——并不意味着语言不允许这样做。此外,这将使您的班级与operator std::string() 进行比较与strings 比较的事物。
  • 正如我在this related question 上评论的那样,操作员通常不需要特权访问。添加对ref(a) &lt; ref(b) 的支持与对operator() 的支持类似,方法是向reference_wrapper 添加包装运算符。此外,我还不清楚依赖隐式转换来应用运算符是否是个好主意。

标签: c++ templates operator-overloading language-lawyer


【解决方案1】:

鉴于此,是否有理由更喜欢非成员函数 我们目前拥有的模板,或者这应该被视为缺陷 在标准中?

原因是 ADL 是否能找到正确的功能。当这样的搜索需要从给定对象的类型中提取替换的模板参数,然后将它们多次替换为函数模板的模板化参数时,ADL 不能这样做,因为在一般情况下没有理由首选模板参数绑定到其他的一种方式。之后定义但仍在该模板的命名空间范围内的非成员函数模板(由于friend)排除了这种不确定性。

【讨论】:

    猜你喜欢
    • 2014-12-07
    • 2010-12-26
    • 2016-08-27
    • 2011-05-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    • 2019-08-08
    相关资源
    最近更新 更多