2015-12-29 9 views
16

Rozważmy następujące klasy:Mniej niż operator poprzez niejawną konwersję?

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

Moje pytanie brzmi:

  • Czy C użytku w standardowych algorytmów jak std::sort że obecnie używa domyślnego operatora <?
  • Czy C uważa się za satysfakcję z koncepcji LessThanComparable?
  • Czy C spełni wymagania hipotetycznej biblioteki algorytmów pojęciowych, która wymagałaby tego typu: LessThanComparable.
+1

Byłem ciekawy i wypróbowałem to. Pracowałem nad C++ 14 tutaj: http://cpp.sh/4hdh –

Odpowiedz

12

Czy C używane w standardowych algorytmów jak std::sort że obecnie używa domyślny < operator?

Tak, działa dla std::sort() i kilku innych standardowych algorytmów. Kod kompilacji:

#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. Spójrz na następne pytanie!

Czy C jest uważany za spełniający koncepcję LessThanComparable?

Lp Wymagania koncepcji LessThanComparable to, że dla obiektów x i y typu C lub const C ekspresji x<y jest ważna i niejawnie zamienny do bool i operator < ustanawia ścisłą słabą relację zamawiania. W twoim przypadku obiekty const nie zostaną przekształcone w int s. To jest błąd w kodzie, ponieważ nie jest poprawny. Dodanie słowa kluczowego const spowoduje jego działanie, a klasa C będzie rzeczywiście LessThanComparable. Zachowana jest ścisła relacja zamawiająca, ponieważ spełniają one ten wymóg.

Will C spełniają wymagania stawiane hipotetycznej conceptified algorytm biblioteki, które wymagałyby typ być LessThanComparable.

Jeśli ustalisz swoją stałość, tak, będzie.

Kilka sidenotes:

  • GCC 4.9 kompiluje x<y nawet jeśli x i y są typu const C. Wydaje się, że jest to błąd kompilatora, ponieważ GCC 5.2 i clang 3.6 powodują tutaj błąd czasu kompilacji.

  • Podanie std::less<C>() jako dodatkowy argument do std::sort() podaje błąd czasu kompilacji, ponieważ funkcja porównywania wymaga, aby obiekty stałe były porównywalne w tym przypadku. Jednak przekazanie std::less<void>() niczego nie psuje, ponieważ argumenty są idealnie przekierowane.

  • Nie wymaga pełnego , ale koncepcji Compare. Ponadto typem iteratora musi być RandomAccessIterator, czyli ValueSwappable, a typ wyodrębniony musi być MoveContructable i MoveAssignable. Tak jest w przypadku pierwszego pytania, nawet jeśli błąd constness nie został naprawiony. Właśnie dlatego działa std::sort() i inne standardowe algorytmy.

+1

O pierwszym punkcie: fakt, że kod się kompiluje i działa w praktyce, nie oznacza, że ​​takie zachowanie jest wymagane przez standard. – chi

+1

@chi Zgadzam się. Dlatego dodałem sidenote na końcu mojej odpowiedzi. Uważam, że wszystkie prawidłowe implementacje standardu muszą kompilować dany kod. –

3

Nie. Kompilator nie może wykonać tak dużej magii, tj. Wywołać metodę rzutowania, a następnie zastosować operator <. Wyobraź sobie, że istnieje kilka operatorów rzutowania dla różnych typów, w jaki sposób kompilator wybrałby właściwy?

EDYCJA: W rzeczywistości nie jest poprawne. Dopóki istnieje operator pojedynczego rzutu, to zadziała. Ale z dwoma lub więcej kompilator będzie narzekać na niejednoznaczne obsady. Jednak takie podejście jest bardzo delikatne, więc generalnie nie jest to dobry pomysł.

+2

Nie mogę się z tobą zgodzić, no nie całkiem. Kompilator wywoła funkcję rzutowania przed zastosowaniem operatora. Stanie się tak, ponieważ operator jest "tylko funkcją", a jeśli obiekt zdefiniował metodę rzutowania lub niejawny konstruktor z jednym argumentem, zostanie rzucony, aby dopasować ten operator. Dwuznaczność kilku operatorów obsady to zupełnie inny temat. – Glapa

+0

@Glapa: Masz rację, sprawdziłem i zadziałało. Tak długo, jak nie dodałem innego operatora obsady. Jednak zaktualizowałem odpowiedź. –

+0

Awansuj do edycji. – ildjarn

2

Próbowałem przykład zaproponowany przez mehrdad momeny. Wszystko działało dobrze. Jednak przy niewielkiej edycji nie działa.

#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

ponieważ będzie to prowadzić do niejasności. Więc nie jest to dobry pomysł, aby to zrobić w ten sposób.

+0

Czy jest zagwarantowane działanie, jeśli jest tylko jeden operator konwersji? – user2079303

+0

Nie mam na to pojęcia, a nie przykładu mehrdad momeny. Powinieneś sięgnąć do standardu –

Powiązane problemy