Меньше оператора через неявное преобразование?

Рассмотрим следующий класс:

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

Мой вопрос:

  • Является ли C пригодным для использования в стандартных алгоритмах, таких как std::sort, который в настоящее время использует значение по умолчанию < оператор?
  • Рассматривается ли C как удовлетворяющая концепции LessThanComparable?
  • Будет ли C соответствовать требованиям гипотетической концептуальной библиотеки алгоритмов, для которой требуется, чтобы тип был LessThanComparable.

Ответы

Ответ 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) );
}

компилирует. Вот живая демонстрация. Посмотрите на следующий вопрос, хотя!

Является ли C рассмотренным как удовлетворяющее концепции LessThanComparable?

Нет. Требования концепции LessThanComparable заключаются в том, что для объектов x и y типа C или const C выражение x<y справедливо и неявно конвертируется в bool, а оператор < устанавливает строгую слабое отношение порядка. В вашем случае объекты const не преобразуются в int s. Это ошибка в коде, потому что она не является корректной. Добавление ключевого слова const заставит его работать, а класс C действительно будет LessThanComparable. Строгое слабое упорядоченное соотношение выполняется, так как int выполняет это требование.

Будет ли C соответствовать требованиям гипотетического концептуального алгоритма библиотеки, для которой требуется, чтобы тип был LessThanComparable.

Если вы исправите свою константу, да, она будет.

Несколько побочных элементов:

  • GCC 4.9 компилирует x<y, даже если x и y имеют тип const C. Это, похоже, ошибка компилятора, поскольку GCC 5.2 и clang 3.6 вызывают ошибку времени компиляции.

  • Передача std::less<C>() в качестве дополнительного аргумента для std::sort() дает ошибку времени компиляции, потому что функция сравнения требует, чтобы в этом случае константные объекты были сопоставимыми. Однако прохождение std::less<void>() ничего не нарушает, поскольку аргументы отлично перенаправляются.

  • std::sort() алгоритм не требует полного LessThanComparable, а концепции Compare. Кроме того, тип итератора должен быть RandomAccessIterator, то есть ValueSwappable, а тип разыменования должен быть MoveContructable и MoveAssignable. Это касается вашего первого вопроса, даже если ошибка constness не исправлена. Вот почему работают std::sort() и другие стандартные алгоритмы.

Ответ 2

Нет. Компилятор не может делать такую ​​большую магию, то есть вызывать метод литья, а затем применять оператор <. Представьте, что для разных типов есть несколько операторов литья, как бы компилятор выбрал правильный?

EDIT: На самом деле это не правильно. До тех пор, пока есть оператор одиночного литья, это будет работать. Но с двумя или более компиляторами будут жаловаться на неоднозначный отбор. Однако этот подход очень хрупок, поэтому в целом это не очень хорошая идея.

Ответ 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

Потому что это приведет к двусмысленности. Таким образом, это не очень хорошая идея.