negacion - ¿Puedes hacer operadores personalizados en C++?
operador condicional en c (5)
¡Sí! (Especie de)
Hay un par de herramientas disponibles públicamente para ayudarlo. Ambos utilizan la generación de código del preprocesador para crear plantillas que implementan los operadores personalizados. Estos operadores consisten en uno o más operadores integrados junto con un identificador.
Como estos no son realmente operadores personalizados, sino simples trucos de sobrecarga del operador, existen algunas advertencias:
- Las macros son malvadas Si comete un error, el compilador será completamente inútil para rastrear el problema.
- Incluso si obtiene la macro correcta, si hay un error en su uso del operador o en la definición de su operación, el compilador será un poco más útil.
- Debe usar un identificador válido como parte del operador. Si desea un operador más parecido a un símbolo, puede usar
_
,o
, o similarmente alfanuméricos simples.
CustomOperators
Mientras trabajaba en mi propia biblioteca para este propósito (ver más abajo) me encontré con este proyecto. Aquí hay un ejemplo de avg
crear un operador avg
:
#define avg BinaryOperatorDefinition(_op_avg, /)
DeclareBinaryOperator(_op_avg)
DeclareOperatorLeftType(_op_avg, /, double);
inline double _op_avg(double l, double r)
{
return (l + r) / 2;
}
BindBinaryOperator(double, _op_avg, /, double, double)
IdOp
Lo que comenzó como un ejercicio de pura frivolidad se convirtió en mi propia opinión sobre este problema. Aquí hay un ejemplo similar:
template<typename T> class AvgOp {
public:
T operator()(const T& left, const T& right)
{
return (left + right) / 2;
}
};
IDOP_CREATE_LEFT_HANDED(<, _avg_, >, AvgOp)
#define avg <_avg_>
Diferencias clave
- CustomOperators admite operadores unarios de posfijo
- Las plantillas IdOp usan referencias en lugar de punteros para eliminar el uso de la tienda gratuita, y para permitir la evaluación completa en tiempo de compilación de la operación
- IdOp le permite especificar fácilmente varias operaciones para el mismo identificador raíz
¿Es posible crear un operador personalizado para que pueda hacer cosas como esta?
if ("Hello, world!" contains "Hello") ...
Nota: esta es una pregunta separada de "¿Es una buena idea ...";)
Hay un método completamente explorado en ''Sypartctic Aspartame'' por Sander Stoks que le permitirá usar el siguiente formato:
if ("Hello, world!" <contains> "Hello") ...
Básicamente, necesita un objeto proxy con los operadores "<" y ">" sobrecargados. El proxy hace todo el trabajo; ''contiene'' puede ser solo un singleton sin comportamiento o datos propios.
// Not my code!
const struct contains_ {} contains;
template <typename T>
struct ContainsProxy
{
ContainsProxy(const T& t): t_(t) {}
const T& t_;
};
template <typename T>
ContainsProxy<T> operator<(const T& lhs, const contains_& rhs)
{
return ContainsProxy<T>(lhs);
}
bool operator>(const ContainsProxy<Rect>& lhs, const Rect& rhs)
{
return lhs.t_.left <= rhs.left &&
lhs.t_.top <= rhs.top &&
lhs.t_.right >= rhs.right &&
lhs.t_.bottom >= rhs.bottom;
}
Para ser un poco más preciso, C ++ solo admite la creación de nuevas sobrecargas de operaciones existentes, NO la creación de nuevos operadores. Hay idiomas (por ejemplo, ML y la mayoría de sus descendientes) que le permiten crear operadores completamente nuevos, pero C ++ no es uno de ellos.
Desde el aspecto de las cosas, (al menos) la biblioteca CustomOperators mencionada en la otra respuesta tampoco es compatible con operadores totalmente personalizados. Al menos, si estoy leyendo las cosas correctamente, está (internamente) traduciendo su operador personalizado en una sobrecarga de un operador existente. Eso facilita las cosas, a expensas de cierta flexibilidad; por ejemplo, cuando crea un nuevo operador en ML, puede darle una prioridad diferente a la de cualquier operador integrado.
Su sugerencia sería nada más que azúcar sintáctica para:
if( contains( "Hello, world!", "Hello" ) ...
y de hecho ya hay una función para hacer eso en cstring y std :: string. ¿Cuál es quizás un poco como responder "es una buena idea?" pero no del todo; más bien preguntando "¿por qué necesitarías / querrías?"
Técnicamente, no. Es decir, no puede extender el conjunto de operator+
, operator-
, etcétera. Pero lo que propones en tu ejemplo es otra cosa. Se está preguntando si existe una definición de "contiene" tal que string-literal "contains" string-literal
es una expresión, con lógica no trivial ( #define contains ""
siendo el caso trivial).
No hay muchas expresiones que puedan tener la forma string-literal X string-literal
. Esto se debe a que los literales de cadena son expresiones. Entonces, estás buscando una regla de lenguaje de la forma expr X expr
. Hay bastantes de ellos, pero todos son reglas para los operadores, y no funcionan en cadenas. A pesar de la implementación obvia, "Hello, " + "world"
no es una expresión válida. Entonces, ¿qué más puede X estar en string-literal X string-literal
? No puede ser una expresión en sí misma. No puede ser un nombre de tipo, un nombre de tipodef o un nombre de plantilla. No puede ser un nombre de función. Realmente solo puede ser una macro, que son las únicas entidades con nombre restantes. Para eso, vea la respuesta "Sí (bueno, más o menos)".