【问题标题】:Less than operator through implicit conversion?通过隐式转换小于运算符?
【发布时间】:2015-12-29 09:17:25
【问题描述】:

考虑以下类:

struct C 
{
     /* Class contents, without any arithmetic operator... */
     constexpr operator int() noexcept; // Implicit conversion to int
};

我的问题是:

  • C 是否可用于标准算法,例如 std::sort,目前使用默认的
  • C 是否满足LessThanComparable 概念?
  • C 是否满足假设的概念化算法库的要求,该算法库要求类型为 LessThanComparable

【问题讨论】:

  • 我很好奇并尝试了它。在这里使用 C++14:cpp.sh/4hdh

标签: c++ implicit-conversion stl-algorithm c++17 c++-concepts


【解决方案1】:

C 是否可用于标准算法,例如当前使用的 std::sort 默认< 运算符?

是的,它适用于std::sort() 和其他一些标准算法。代码

#include <algorithm>
#include <vector>

struct C 
{
     /* Class contents, without any arithmetic operator... */
     constexpr operator int() noexcept {return 0;} // Implicit conversion to int
};

int main()
{
    std::vector<C> v;  
    std::sort( begin(v), end(v) );
}

编译。 Here's a live demo. 不过看下一个问题!

C 是否被认为满足 LessThanComparable 概念?

没有。 LessThanComparable 概念的要求是,对于 Cconst C 类型的对象 xy,表达式 x&lt;y 是有效的并且可以隐式转换为 bool 并且 &lt; 运算符建立严格弱排序关系。在您的情况下, const 对象不会转换为 ints。这是您的代码中的一个错误,因为它不是 const 正确的。添加const 关键字将使其工作,而C 类确实是LessThanComparable。满足严格的弱排序关系,因为ints 满足了这个要求。

C 是否满足假设概念化算法的要求 要求类型为 LessThanComparable 的库。

如果你修复你的 constness,是的,它会的。

一些旁注:

  • 即使xy 的类型为const C,GCC 4.9 也会编译x&lt;y。这似乎是一个编译器错误,因为 GCC 5.2 和 clang 3.6 在这里抛出了编译时错误。

  • std::less&lt;C&gt;() 作为额外参数传递给std::sort() 会产生编译时错误,因为在这种情况下,比较函数要求常量对象具有可比性。然而,传递std::less&lt;void&gt;() 并不会破坏任何东西,因为参数被完美地转发了。

  • std::sort() algorithm 不需要完整的LessThanComparable,而是概念Compare。此外,迭代器类型必须是RandomAccessIterator,即ValueSwappable,而取消引用的类型必须是MoveContructableMoveAssignable。这就是您的第一个问题的全部情况,即使没有修复 constness 错误。这就是 std::sort() 和其他标准算法起作用的原因。

【讨论】:

  • 关于第一点:代码在实践中编译和工作的事实并不意味着这种行为是标准规定的。
  • @chi 我同意。这就是为什么在我的答案末尾添加了一个旁注。我相信标准的所有正确实现都必须编译给定的代码。
【解决方案2】:

没有。编译器不能做这么大的魔术,即调用 cast 方法然后应用 &lt; 运算符。想象一下,对于不同的类型有几个强制转换运算符,编译器将如何选择合适的一个?

编辑:实际上它是不正确的。只要有单一演员表操作员,这将工作。但是有两个或更多编译器会抱怨模棱两可的演员表。但是,这种方法非常脆弱,因此总的来说不是一个好主意。

【讨论】:

  • 我不能同意你的看法,也不完全同意。编译器将在应用运算符之前调用 cast。这会发生,因为运算符“只是一个函数”,如果对象定义了强制转换方法或带有一个参数的隐式构造函数,它将被强制转换以匹配该运算符。几个演员的歧义是完全不同的话题。
  • @Glapa:你说得对,我检查过了,它奏效了。只要我没有添加另一个演员表操作员。不过我更新了答案。
【解决方案3】:

我尝试了mehrdad momeny提出的例子。它工作得很好。但是,只要稍加编辑,它就不再工作了。

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

struct C 
{
    C(int x):X(x){}
    operator int() { return X; }
    operator float() { return static_cast<float>(X); }

    int X;
};

using namespace std;

int main()
{
    vector<C> u = {1, 2, 35, 6, 3, 7, 8, 9, 10};
    sort(u.begin(), u.end());
    for(auto x: u){
        cout << x << endl;
    }
}

Live Demo

因为这会导致歧义。因此,这样做并不是一个好主意。

【讨论】:

  • 那么,如果只有一个转换运算符,它是否保证工作?
  • 我对此一无所知,而不是 mehrdad momeny 的例子。你应该深入研究标准
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 2019-01-08
  • 2013-08-25
  • 1970-01-01
  • 2017-07-04
  • 1970-01-01
相关资源
最近更新 更多