Есть ли более короткий способ написания `StringPtr?StringPtr: "null" `? - PullRequest
4 голосов
/ 16 августа 2011

У меня есть этот код:

 std::wstringstream outstream;
 outstream << (prop.m_pwszOriginalVolumeName 
             ? prop.m_pwszOriginalVolumeName 
             : L"null") << L";"
           << (prop.m_pwszSnapshotDeviceObject 
             ? prop.m_pwszSnapshotDeviceObject 
             : L"null") << L";"
           << (prop.m_pwszOriginatingMachine 
             ? prop.m_pwszOriginatingMachine
             : L"null") << L";"
           << ... // some more strings here

Есть ли способ избежать дублирования кода и при этом иметь краткий код?

Ответы [ 5 ]

6 голосов
/ 16 августа 2011

Вы можете определить небольшую функцию:

whatever_t strOrNull(whatever_t str) {
    return str ? str : L"null";
}

Тогда ваш код станет

std::wstringstream outstream;
outstream << strOrNull(prop.m_pwszOriginalVolumeName)   << L";"
          << strOrNull(prop.m_pwszSnapshotDeviceObject) << L";"
          << strOrNull(prop.m_pwszOriginatingMachine)   << L";"
          << ... // some more strings here

Или, если вы хотите быть еще более кратким, вы можете сделать это (в зависимости от того, чтоwhatever_t есть; если wstringstream уже имеет перегрузку operator<< для этого типа, это не сработает):

wstringstream& operator<<(wstringstream& out, whatever_t str) {
    if (str)
        out << str;
    else
        out << L"null";

    return out;
}

Тогда ваш код становится

std::wstringstream outstream;
outstream << prop.m_pwszOriginalVolumeName   << L";"
          << prop.m_pwszSnapshotDeviceObject << L";"
          << prop.m_pwszOriginatingMachine   << L";"
          << ... // some more strings here
2 голосов
/ 16 августа 2011

Другие примеры действительно хороши. Есть и другой вариант, хотя я бы его не рекомендовал (упомяну только для полноты).

GCC имеет расширение под названием «Условные выражения с опущенными операндами», которое в основном выглядит следующим образом:

x = a ?: b;

, что аналогично (в таких простых случаях, как ваш, для получения дополнительной информации см. Ниже):

x = a ? a : b;

Просто менее портативный. Таким образом, вы могли бы написать:

std::wstringstream outstream;
outstream << (prop.m_pwszOriginalVolumeName   ?: L"null") << L";"
          << (prop.m_pwszSnapshotDeviceObject ?: L"null") << L";"
          << (prop.m_pwszOriginatingMachine   ?: L"null") << L";"

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

На самом деле есть случай, когда он работает не так, как обычный троичный if, и это если оценка a имеет побочные эффекты. Со страницы:

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

См. http://gcc.gnu.org/onlinedocs/gcc/Conditionals.html

2 голосов
/ 16 августа 2011

Вы можете использовать вспомогательную функцию:

const wchar_t *SafeOutput(const wchar_t *str)
{
    return str ? str : L"null";
}
// Analogous function for ANSI strings
...
outstream << SafeOutput(prop.m_pwszOriginalVolumeName)   << L";"
          << SafeOutput(prop.m_pwszSnapshotDeviceObject) << L";"
          << SafeOutput(prop.m_pwszOriginatingMachine)   << L";"
          << ... // more strings here
2 голосов
/ 16 августа 2011

Простая функция должна помочь.

wchar_t* filterNullString(wchar_t* str)
{
  static wchar const* nullStr = L"null";
  return str ? str : nullStr;
}

std::wstringstream outstream;
outstream << filterNullString(prop.m_pwszOriginalVolumeName) << L";"
           << filterNullString(prop.m_pwszSnapshotDeviceObject)<< L";"
           << filterNullString(prop.m_pwszOriginatingMachine)<< L";" ;
2 голосов
/ 16 августа 2011

Функция или лямбда:

auto foo = [](const wchar * p) { return p ? p : L"null;" };

outstream << foo(prop.m_pwszOriginalVolumeName) << L";"
          << foo(prop.m_pwszSnapshotDeviceObject) << L";"
          << ...etc...
...