Подтвердить что ты не робот

С# нулевой коалесцирующий оператор-эквивалент для С++

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

4b9b3361

Ответ 1

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

в С# оператор определяется как

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

Итак, метод С++ будет выглядеть как

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

Ответ 3

Использование шаблонов и С++ 11 lambdas. Первый аргумент (левая часть) оценивается только один раз. Второй аргумент (правая сторона) оценивается только в том случае, если первый является ложным (обратите внимание, что "if" и "?" Статически передают предоставленное выражение в bool и что указатели имеют "явный оператор bool() const", который является равным to '!= 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' в консоли. Чтобы написать лямбда для rhs, есть немного шаблона

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

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

Ответ 4

Как насчет этого?

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

Ответ 5

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

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

Надеюсь, это поможет.

Ответ 6

Существует расширение GNU GCC, позволяющее использовать оператор ?: с отсутствующим средним операндом, см. Условия с пропущенными операндами.

Средний операнд в условном выражении может быть опущен. Тогда если первый операнд ненулевой, его значение является значением условное выражение.

Поэтому выражение

x ? : y

имеет значение x, если оно отлично от нуля; в противном случае значение y.

Этот пример совершенно эквивалентен

x ? x : y

В этом простом случае возможность опустить средний операнд не особенно полезен. Когда это становится полезным, это когда первый операнд содержит или может (если это макрос-аргумент) содержать сторону эффект. Затем повторение операнда в середине будет выполнять побочный эффект в два раза. Пропуск среднего операнда уже использует значение вычисляется без нежелательных последствий его пересчета.

Это расширение также поддерживается clang. Тем не менее, перед использованием расширения вы должны уточнить у используемого вами компилятора и требования переносимости кода. Примечательно, что компиляторы MSVC C++ не поддерживают опущенные операнды в ?:.

Смотрите также связанное обсуждение Кару здесь.