C++ Как уменьшить повторение кода для подобных классов


У меня есть следующие два класса, чтобы сделать добавление stringS - и wstringС соответственно - легче:

#include <string>
#include <sstream>

class StringBuilder
{
public:
    template <typename T>
    StringBuilder& operator<<(const T& t)
    {
        this->stream << t;
        return *this;
    }

    operator std::string() const;

private:
    std::ostringstream stream;
};

StringBuilder::operator std::string() const
{
    return this->stream.str();
}

class WStringBuilder
{
public:
    template <typename T>
    WStringBuilder& operator<<(const T& t)
    {
        this->stream << t;
        return *this;
    }

    explicit operator std::wstring() const;

private:
    std::wstringstream stream;
};

WStringBuilder::operator std::wstring() const 
{
    return this->stream.str();
}

Теперь, как видите, почти весь код (кроме бетона string и stringstream типов) повторяется, особенно операторы.

Вопрос:

  • Есть ли способ, чтобы уменьшить дублирование кода? Я думала о базовом классе, шаблоны и специализации, но проблема я не знаю как правильно определить stringstream тип в зависимости от string типа потом.


629
7
задан 10 февраля 2018 в 12:02 Источник Поделиться
Комментарии
1 ответ

Да, есть. На самом деле, очень хороший способ решить эту избыточность кода вопрос приходит на ум, если учесть, что std::string Это просто типа псевдоним std::basic_string<char> и std::wstring псевдоним std::basic_string<wchar_t>. Кроме того, std::stringstream и std::wstringstream также просто псевдонимы std::basic_stringstream<char> и std::basic_stringstream<wchar_t>соответственно. Это позволяет легко шаблонного подхода к проблеме.

Что действительно для меня напрашивается-это псевдоним шаблона-база-тип рисунка от стл (хотя могут быть и другие допустимые подходы), реализация которых могла бы выглядеть примерно так:

#include <sstream>
#include <string>

namespace impl {

template <typename CharType>
class StringBuilderImpl {

std::basic_stringstream<CharType> stream;

public:
template <typename T>
StringBuilderImpl& operator<<(T const& t) {
stream << t;
return *this;
}

operator std::basic_string<CharType>() const {
return stream.str();
}
};
}

using StringBuilder = impl::StringBuilderImpl<char>;
using WStringBuilder = impl::StringBuilderImpl<wchar_t>;

StringBuilderImpl соответствует несколько std::basic_[string/stringstream] и принимает базовый символьный тип в качестве аргумента шаблона. Ваш бывший классов StringBuilder и WstringBuilder теперь только псевдонимы для некоторых шаблонов специализации, как std::[string/wstring] и std::[stringstream/wstringstream] являются.

(В моем коде, StringBuilderImpl вроде спрятан внутри impl пространства имен. Если это ваша потребность, тем не менее, вы могли бы также сделать его частью открытого интерфейса программы библиотеки, что обеспечивает дополнительные технические требования, такие как StringBuilderImpl<char16_t>)

14
ответ дан 10 февраля 2018 в 02:02 Источник Поделиться