Функция-член C ++ toString и оператор ostream << интеграция через шаблоны - PullRequest
2 голосов
/ 29 апреля 2011

Я начинающий разработчик C ++, и у меня есть вопрос об интеграции операторов toString и ostream через шаблоны.У меня есть такой код:

    struct MethodCheckerTypes{
        typedef unsigned char TrueType;
        typedef long FalseType;
    };
    template<typename T>struct HasToString{
        template<typename K>static typename MethodCheckerTypes::TrueType test(decltype(&K::toString));
        template<typename> static typename MethodCheckerTypes::FalseType test(...);
        static const bool value = sizeof(test<T>(0)) == sizeof(typename MethodCheckerTypes::TrueType);
        typedef decltype(test<T>(0)) ValueType;
    };

    template<typename T, typename K> struct IfDef{};
    template<> struct IfDef<typename MethodCheckerTypes::TrueType, ostream&>{
        typedef ostream& type;
    };

    class WithToString{
    public:
        string toString() const{
            return "hello";
        }
    };

    template<typename F, typename CharT, typename Traits> typename IfDef<typename HasToString<F>::ValueType, basic_ostream<CharT, Traits>&>::type operator<<(basic_ostream<CharT, Traits>& out, const F &ref){
        out<<ref.toString().c_str();
        return out;
    }
int main(int argc, char **argv){
    WithToString hasToString;
    cout<<hasToString<<endl;
    return 0;
}

Код был скомпилирован без ошибок, и приложение выполнено успешно.Хорошо ли использовать такой подход?Я хотел реализовать это без какой-либо помощи от boost.

Ответы [ 2 ]

1 голос
/ 29 апреля 2011

Подход к реализации operator<< сам по себе нормален.Но использование частей языка, который вы не понимаете, является плохой практикой (я не верю, что новичок может написать такой код).У вас есть две альтернативы: реализовать функцию-член toString или перегрузить operator<<(std::ostream&, T).Последний подход позволяет использовать boost::lexical_cast для преобразования объекта в строку.Что касается меня, последний подход больше C ++ ish, если вы можете сделать что-то без функции-члена, лучше сделать это.

0 голосов
/ 05 марта 2017

Я использовал подход, использующий оператор потока перегрузки решения @Begemoth <<, а затем добавил удобный метод "mixin" класса "toString" в тех случаях, когда требуется немедленная строка, например для отладки: </p>

template<typename T>
class ToString
{
public:
    std::string toString() const
    {
        return convertToString(static_cast<const T&>(*this));
    }
};

template<typename T>
inline std::string convertToString(const T& value)
{
    std::stringstream s;
    s << value;
    return s.str();
}

Затем вы можете наследовать от этого класса в тех случаях, когда у вас есть оператор ostream, и он предоставит вам метод toString для этого класса.Если вы используете boost, то вы можете заменить реализацию convertToString, используя lexical_cast:

template<typename T>
inline std::string convertToString(const T& value)
{
    return boost::lexical_cast<std::string>(value);
}

Если ваш класс предназначен для наследования и полиморфного доступа через указатели, то вышеупомянутое решение не будет работать, поскольку шаблоны связаны во время компиляциитак что нужен другой подход.Следующий класс mixin может использоваться вместо «ToString» выше, где определен виртуальный метод.Затем предоставляется вспомогательный макрос для реализации виртуальной функции в терминах функции шаблона "convertToString".Это должно быть добавлено в тело класса каждого производного класса, так как оно должно быть переопределено, а указатель «this» статически привязан к текущему типу.

class ToStringVirtual
{
public:
    virtual ~ToStringVirtual() {}
    virtual std::string toString() const = 0;
};

#define IMPLEMENT_ToStringVirtual public: std::string toString() const override { return convertToString(*this); }
...