How to convert anything to string implicitly?

后端 未结 2 1328
失恋的感觉
失恋的感觉 2021-01-06 06:25

My goal is to design a String class that decorates std::string in order to provide some functionality my program needs. One functionality I want to add is the ability to con

相关标签:
2条回答
  • 2021-01-06 06:53

    This or similar should fix it:

    namespace HasFormattedOutput {
    
        namespace Detail
        {
            struct Failure{};
        }
    
        template<typename OutputStream, typename T>
        Detail::Failure operator << (OutputStream&, const T&);
    
        template<typename OutputStream, typename T>
        struct Result : std::integral_constant<
            bool,
            ! std::is_same<
                decltype((*(OutputStream*)0) << std::declval<T>()),
                Detail::Failure
            >::value
        > {};
    } // namespace HasFormattedOutput
    
    template <typename T, typename OutputStream = std::ostream>
    struct has_formatted_output
    :   HasFormattedOutput::Result<OutputStream, T>
    {};
    
    class X  {
        public:
        X() {}
    
        template <typename T>
        X(const T& t) {
            static_assert(
                 has_formatted_output<T>::value, 
                 "Not supported type.");
            std::ostringstream s;
            s << t;
            str = s.str();
        }
    
        private:
        std::string str;
    };
    std::ostream& operator << (std::ostream& stream, const X&) { return stream; }
    
    struct Y  {
        Y() {}
    };
    
    int main() {
        Y y;
        X x(y);
        return 0;
    }
    
    0 讨论(0)
  • 2021-01-06 07:11

    Instead of declaring the output operator in the surrounding namespace, only declare it as a friend of the String class:

    class String {
    public:
        // This must be implemented inline here
        friend std::ostream& operator<<(std::ostream& o, const String& s) {
            return o << _str; // for example
        }
    
        template<typename t_value>
        String(t_value value) {
           std::ostringstream oss;
           oss << value;
          _str = oss.str();
        }
    private:
        std::string _str;
    };
    

    Now it can only be found by argument-dependent lookup, and so will only be considered if the second argument really is of type String, not just convertible to it. Therefore, it won't be considered as a candidate for os << value in the constructor, giving a compile error rather than a run-time death spiral if there is no other candidate.

    0 讨论(0)
提交回复
热议问题