Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: VincentОтветов: 3

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

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 Mehrdad 29.12.2015

c++c++17implicit-conversionc++-conceptsstl-algorithm

Ответы

Ответ 1 · рейтинг 12 · Ralph Tandetzky

Можно ли 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 не будут преобразованы в ints. Это ошибка в вашем коде, потому что она некорректна. Добавление ключевого слова const заставит его работать, и класс C действительно будет LessThanComparable. Отношение строгого слабого порядка выполняется, потому что ints удовлетворяют этому требованию.

Будет ли 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. Это все, что касается вашего первого вопроса, даже если ошибка константности не исправлена. Вот почему работают std::sort() и другие стандартные алгоритмы.

Ответ 2 · рейтинг 3 · Zbynek Vyskovsky - kvr000

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

РЕДАКТИРОВАТЬ: На самом деле это неправильно. Пока есть оператор одиночного приведения, это будет работать. Но с двумя или более компилятор будет жаловаться на неоднозначное приведение. Однако этот подход очень хрупкий, поэтому в целом это не лучшая идея.

Ответ 3 · рейтинг 2 · Humam Helfawi

Я попробовал пример, предложенный 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;
    }
}

Живая демонстрация

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы