15

Rozważmy następujący struct (?):Pustka(), operator przecinek (operator) i niemożliwe przeciążenia

struct S {}; 

w C++ 14, definicja poniżej jest poprawny:

constexpr auto f() { return S{}, 'c'; } 

jak również po jednym:

constexpr auto f() { return S{}, void(); } 

teraz rozważmy następujący fragment roboczą, która obejmuje pierwszy z dwóch definicji :

#include<type_traits> 

struct S {}; 

constexpr int operator,(S, char) { return 42; } 
constexpr auto f() { return S{}, 'c'; } 

int main() { 
    constexpr int i{f()}; 
    static_assert(i == 42, "!"); 
    static_assert(std::is_same<decltype(f()), int>::value, "!"); 
} 

nie Mówiąc tak technicznie, przeciążenie operatora przecinkami przechwytuje para S{}, 'c' i zwraca liczbę całkowitą, jak poprawnie zweryfikowany w funkcji main.

Teraz załóżmy, że chcę zrobić to samo z drugą definicją f:

constexpr auto f() { return S{}, void(); } 

W tym przypadku operator przecinek powinien przechwytujący forma S{}, void().
Ani następujących utworów Definition (z oczywistych powodów):

constexpr int operator,(S, void) { return 42; } 

Ani jeden poniżej (które pracowały w poprzednim przypadku):

template<typename T> constexpr int operator,(S, T &&) { return 42; } 

Czy istnieje jakiś sposób, aby przeładowywać przecinek operator, aby poradzić sobie z S{}, void()?
Czy nie jest to inaczej brak standardu, ponieważ pozwala on w ten sposób korzystać z operatora przecinka, ale nie daje możliwości przeciążenia tego samego operatora (nawet jeśli the standard mentions that overloaded functions involving S are allowed)?


Uwaga: kwestia ta jest wykonana ze względu na ciekawość. Proszę, unikaj komentarzy, takich jak , nie rób tego lub to nie jest dobra praktyka. Nie zamierzam tego robić w środowiskach produkcyjnych. Dziękuję Ci.

+2

To intrygująco szalone;) –

+0

@JesperJuhl Tak, wiem. Standardowa partyzantka. Odkrywam najbardziej niejasne zakątki tego języka. :-) – skypjack

+0

Zmiana operatora ',' na '+' daje "argument może nie mieć 'void' type" error. – kennytm

Odpowiedz

20

Odpowiedni punkt na to 13.3.1.2/9 [over.match.oper] w N4140:

Jeżeli operator jest operatorem , The operatorem, & lub operator ->, i nie istnieją żadne realne funkcje następnie operator zakłada się wbudowaną operatora i interpretowane zgodnie z § 5.

Jak void() nigdy nie jest poprawnym argumentem funkcji (patrz 5.2.2/7 [expr .call]), tam ne ver jest sprawną funkcją, dlatego zostanie użyty wbudowany ,.

Więc nie, to, co próbujesz zrobić, nie jest możliwe.

W rzeczywistości, pisanie pętli iteracyjnej jak ten

for(...; ++it1, (void)++it2) 

to standardowy sposób, aby uniemożliwić użytkownikom łamanie kodu przeciążenia , dla swoich typów iterator egzekwując wbudowanego operatora , być używany. (Zauważ, że nie mówię, trzeba to zrobić w swoim codziennym kodu To bardzo dużo zależy od jego faktycznego wykorzystania Jest to standardowy poziom biblioteka paranoję...)


Odnośnie standardowej klauzuli jesteś powiązany:

znaczenie operatorów =, (jednoskładnikowa) &, a, (przecinek), predefiniowane dla każdego typu, mogą być zmienione dla poszczególnych klas i typów wyliczeniowych poprzez zdefiniowanie funkcji operatorskich, które implementują te podmioty.

Ale takiej funkcji nie można zdefiniować, ponieważ, jak już wspomniałem powyżej, void() nigdy nie jest prawidłowym argumentem funkcji.

To, czy jest to niedopatrzenie/problem w standardzie, jest otwarte do debaty.

+2

Interesujące użycie '(void)' w pętli, aby uniknąć wywoływania przeciążonego przecinka. Dzięki za wskazówkę! – paulotorrens