overload operator assignment c++ operator-overloading language-lawyer void comma-operator

c++ - operator - El vacío(), el operador de coma(operador) y la sobrecarga imposible(?)



overload operator c++ (1)

Considere la siguiente estructura:

struct S {};

En C ++ 14, la siguiente definición es válida:

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

Así como el siguiente:

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

Ahora, considere lo siguiente, fragmento de trabajo que involucra la primera de las dos definiciones:

#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, "!"); }

Hablando no tan técnicamente, la sobrecarga del operador de coma intercepta la pareja S{}, ''c'' y devuelve un entero, como se verifica correctamente en la función main .

Ahora, supongamos que quiero hacer lo mismo con la segunda definición de f :

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

En este caso, el operador de coma debe interceptar el formulario S{}, void() .
Ninguna de las siguientes definiciones funciona (por razones obvias):

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

Ni el de abajo (que hubiera funcionado en el caso anterior):

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

¿Hay alguna manera de sobrecargar al operador de coma para tratar con S{}, void() ?
De lo contrario, ¿no es una falta en el estándar, ya que permite usar el operador de coma de esa manera, pero no le da la oportunidad de sobrecargar al mismo operador (incluso si el estándar menciona que las funciones sobrecargadas que involucran S están permitidas )?

Nota : esta pregunta está hecha por el bien de la curiosidad. Por favor, evite comentarios como no haga eso o no es una buena práctica . No estoy planeando hacer eso en entornos de producción. Gracias.


La cláusula relevante para esto es 13.3.1.2/9 [over.match.oper] en N4140:

Si el operador es el operador , el operador unario & , o el operador -> , y no hay funciones viables, se supone que el operador es el operador integrado y se interpreta de acuerdo con la Cláusula 5.

Como void() nunca es un argumento de función válido (ver 5.2.2 / 7 [expr.call]), nunca hay una función viable y, por lo tanto , se utilizará la función incorporada.

Así que no, lo que estás tratando de hacer no es posible.

De hecho, escribiendo un bucle de iterador como este

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

es una forma estándar de evitar que los usuarios rompan su código mediante la sobrecarga , para sus tipos de iteradores mediante la aplicación del operador integrado , que se utilizará. (Tenga en cuenta que no estoy diciendo que tenga que hacer esto en su código diario. Depende mucho de su uso real. Este es el nivel de paranoia estándar de la biblioteca).

Respecto a la cláusula estándar que vinculaste:

El significado de los operadores =, (unario) &, y, (coma), predefinido para cada tipo, se puede cambiar para clases específicas y tipos de enumeración definiendo funciones de operador que implementan estos operadores .

Pero tal función no se puede definir porque, como dije anteriormente, void() nunca es un argumento de función válido.

Ahora, si esto es o no un descuido / problema en la norma está abierto a debate.