2009-11-23 20 views

Respuesta

12

No hay una manera de hacer esto de forma predeterminada en C++, pero se puede escribir uno:

en C# del ?? operador se define como

a ?? b === (a != null ? a : b) 

Por lo tanto, el método C++ se vería

Coalesce(a, b) // put your own types in, or make a template 
{ 
    return a != null ? a : b; 
} 
+12

En este método b se evalúa incluso si a no es nulo. Esto podría ser un problema si b tiene efectos secundarios. – Amnon

+3

@Amnon: De hecho. Considere: 'p = Coalesce (p, new int (10));'. Además, parece que en C#, el operando de la derecha no puede ser NULL (no se puede verificar en tiempo de compilación, ya que no hay ningún tipo de NULL en C++). Por otro lado, ¿existe tanta necesidad en C++, por lo que no puede simplemente escribir 'a? a: b; '? – UncleBens

+1

Y si es C++ 11 o superior, use 'nullptr'. No hay 'null' en C/C++ de todos modos, solo' NULL' se define en algunos encabezados. http://stackoverflow.com/questions/1282295/what-excaly-is-nullptr –

2

¿Qué tal esto?

#define IFNULL(a,b) ((a) == null ? (b) : (a)) 
+2

cuidado con IFNULL (a ++, b) Sí, me doy cuenta de que querrías tener cuidado con eso de todos modos si crees que podría ser nulo. IFNULL (SomeClass.DoSomethingReallyLong(), "") causa problemas también. – McKay

+0

Buen punto-- me sirve para ser flojo. Usar un método de plantilla definitivamente es el camino a seguir aquí, ya que evita los efectos secundarios y tendrá un rendimiento equivalente (o mejor). Voy a agregar un +1 en la solución de @ McKay ahora. :-) –

+3

Una plantilla de función no tiene necesariamente un rendimiento igual o mejor. Estos "cortocircuitos" ("b" no se evalúan a menos que "a" sea nulo), mientras que los argumentos de una función siempre se evalúan. –

1

Uso de plantillas y C++ 11 lambdas. El primer argumento (lado izquierdo) solo se evalúa una vez. El segundo argumento (lado derecho) solo se evalúa si el primero es falso (tenga en cuenta que 'if' y '?' Expresan estáticamente la expresión proporcionada a bool, y que los punteros tienen 'operador explícito bool() const' que es equalivent a '! = nullptr')

template<typename TValue, typename TSpareEvaluator> 
TValue 
coalesce(TValue mainValue, TSpareEvaluator evaluateSpare) { 

    return mainValue ? mainValue : evaluateSpare(); 
} 

Ejemplo de uso

void * const  nonZeroPtr = reinterpret_cast<void *>(0xF); 
void * const otherNonZeroPtr = reinterpret_cast<void *>(0xA); 

std::cout << coalesce(nonZeroPtr, [&]() { std::cout << "Never called"; return otherNonZeroPtr; }) << "\n"; 

se acaba de imprimir '0xf' en la consola. Tener que escribir una lambda de los RHS es un poco repetitivo de

[&]() { return <rhs>; } 

pero es lo mejor que uno puede hacer si uno carece de apoyo de la sintaxis del lenguaje.

+0

Esta es la única respuesta que ofrece la semántica idéntica de un operador coalescente nulo. Sin embargo, probablemente nunca valga la pena el alboroto. Realmente, esta característica solo necesita estar en el idioma. –

1

Sólo quiero ampliar la respuesta de @Samuel García mediante la generalización de la plantilla y la adición de macros de ayuda para reducir el lambda repetitivo:

#include <utility> 

namespace coalesce_impl 
{ 
    template<typename LHS, typename RHS> 
    auto coalesce(LHS lhs, RHS rhs) -> 
     typename std::remove_reference<decltype(lhs())>::type&& 
    { 
     auto&& initialValue = lhs(); 
     if (initialValue) 
      return std::move(initialValue); 
     else 
      return std::move(rhs()); 
    } 

    template<typename LHS, typename RHS, typename ...RHSs> 
    auto coalesce(LHS lhs, RHS rhs, RHSs ...rhss) -> 
     typename std::remove_reference<decltype(lhs())>::type&& 
    { 
     auto&& initialValue = lhs(); 
     if (initialValue) 
      return std::move(initialValue); 
     else 
      return std::move(coalesce(rhs, rhss...)); 
    } 
} 

#define COALESCE(x) (::coalesce_impl::coalesce([&](){ return (x); })) 
#define OR_ELSE ); }, [&](){ return (

El uso de las macros, puede simplemente:

int* f(); 
int* g(); 
int* h(); 

int* x = COALESCE(f() OR_ELSE g() OR_ELSE h()); 

I espero que esto ayude.