2009-11-23 4 views
16

Есть ли эквивалент C++ для оператора C# null коалесцирования? Я делаю слишком много нулевых проверок в моем коде. Так что искал способ уменьшить количество нулевого кода.C# null коалесцирующий оператор эквивалент для C++

+7

В GCC это 'a?: B', но это не переносится. – MSalters

ответ

12

Существует не способ сделать это по умолчанию в C++, но вы могли бы написать один:

в C# на ?? оператор определяется как

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

Таким образом, метод C++ будет выглядеть

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

В этом методе b вычисляется, даже если a не является нулевым. Это может быть проблемой, если b имеет побочные эффекты. – Amnon

+3

@Amnon: Действительно. Рассмотрим: 'p = Coalesce (p, new int (10));'. Кроме того, похоже, что в C# правый операнд не может быть NULL (не может быть проверен во время компиляции, так как в C++ нет нулевых типов?). С другой стороны: есть ли такая потребность в C++, так что вы не можете просто набрать 'a? a: b; '? – UncleBens

+1

И если это C++ 11 или выше, используйте 'nullptr'. В любом случае в C/C++ нет «null», в некоторых заголовках определяется только «NULL». http://stackoverflow.com/questions/1282295/what-exactly-is-nullptr –

2

Как об этом?

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

Остерегайтесь IFNULL (a ++, b) Да, я понимаю, вы бы хотели остерегаться этого, если вы думаете, что может быть пустым. IFNULL (SomeClass.DoSomethingReallyLong(), "") также вызывает проблемы. – McKay

+0

Хорошая точка - служит мне для того, чтобы быть ленивым. Использование метода шаблона - это, безусловно, способ пойти сюда, поскольку он избегает побочных эффектов и будет иметь эквивалентную производительность (или лучше). Я собираюсь добавить +1 на решение @ McKay. :-) –

+3

Шаблон функции не обязательно должен иметь равную или лучшую производительность. Это «короткое замыкание» ('b' не оценивается, если' a' равно null), тогда как аргументы функции всегда оцениваются. –

1

Использование шаблонов и C++ 11 lambdas. Первый аргумент (левая часть) оценивается только один раз. Второй аргумент (правая сторона) оценивается только в том случае, если первый является ложным (обратите внимание, что «if» и «?» Статически передают предоставленное выражение в bool и что указатели имеют «явный оператор bool() const», который является равным к '! = nullptr')

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

    return mainValue ? mainValue : evaluateSpare(); 
} 

Пример использования

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"; 

Будет просто напечатать '0xf' в консоли. Имея написать лямбда для ОРЗ является немного шаблонный

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

, но это лучшее, что можно сделать, если один не имеет поддержки со стороны синтаксиса языка.

+0

Это единственный ответ, который предлагает идентичную семантику оператора нулевой коалесценции. Это, вероятно, редко стоит суета. Действительно, эта функция просто должна быть на языке. –

1

Просто хочу, чтобы расширить ответ @Samuel Гарсиа Обобщая шаблон и добавить вспомогательные макросы, чтобы сократить лямбда шаблонного:

#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 (

Используя макросы, вы можете просто:

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

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

I надеюсь это поможет.

Смежные вопросы