【问题标题】:C++ toString member-function and ostream operator << integration via templatesC++ toString 成员函数和 ostream 运算符 << 通过模板集成
【发布时间】:2011-04-29 11:22:44
【问题描述】:

我是一名初学者 C++ 开发人员,我有一个关于通过模板集成 toStringostream 运算符的问题。 我有这样的代码:

    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 帮助的情况下实现它。

【问题讨论】:

  • 你是一个初学者并从一开始就开始使用模板(C++最危险的特性)?
  • 你似乎是一个非常进步的初学者。 :) 进展顺利。
  • 谢谢。我想说我是初学者模板开发人员。而且这段代码sn-p使用了C++0x特性(decltype)。
  • 这个问题可能更适合 codereview.stackexchange.com

标签: c++ templates c++11 ostream sfinae


【解决方案1】:

单独实现operator&lt;&lt; 的方法是正常的。但是使用您不理解的部分语言是不好的做法(我不相信初学者可以编写这样的代码)。您有两种选择:实现toString 成员函数或重载operator&lt;&lt;(std::ostream&amp;, T)。后一种方法使您可以使用boost::lexical_cast 将对象转换为字符串。至于我,后一种方法更 C++ish,如果你可以在没有成员函数的情况下做某事,那就更好了。

【讨论】:

  • 谢谢!我想要无 BOOST 的方法。关于第一个建议:您的意思是我的所有类都必须从带有 toString 的基本抽象类继承。我想过这样的方式,但想要更通用的解决方案。
  • @Malasar,从这样的通用类继承似乎毫无意义(除非类型系统强迫你这样做)。 BOOSTless 方法boost::lexical_cast 使用std::stringstream 做转换怎么样(一般情况下),实现类似的功能并不难。
  • 知道了!我会检查 lexical_cast 方式。非常感谢您的回复!
  • 刚刚查看了自定义类的 lexical_cast 用法。非常有趣的解决方案。
  • @Malasar,如果您对解决方案感到满意,那么您可以在作者答案下方打勾。
【解决方案2】:

我采用@Begemoth 解决方案重载流运算符

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,那么您可以使用 lexical_cast 替换 convertToString 的实现:

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); }

【讨论】:

    猜你喜欢
    • 2016-08-27
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-05
    相关资源
    最近更新 更多