How to convert a template type to string if it can be a string too?

  • A+

I have class:

template <typename val_t> class tracer_t : public base_tracer_t<val_t> {     std::vector<std::string> m_trace; public:     virtual void push_fact(val_t fact) override {         std::string str = "+ fact: " + to_string(fact);         m_trace.push_back(std::move(str));     }      virtual void push_rule(const std::string &id, val_t val, bool tg) override {         std::string str = "+ ";         if (tg) { str += "target: "; }         else { str += "rule: "; }         str += id + " -> " + to_string(val);         m_trace.push_back(std::move(str));     }      virtual void print() override {         std::cout << "Stack trace: " << std::endl;         for (auto it = m_trace.begin(); it != m_trace.end(); ++it) {             std::cout << (*it) << std::endl;         }     } private:     std::string to_string(val_t val) {         if (std::is_same<val_t, std::string>::value) {             return (std::string)val;         }         return std::to_string(val);     } }; 

The problem is that it doesn't compile if val_t is std::string because of:

tracer.hpp:49: error: no matching function for call to ‘to_string(std::__cxx11::basic_string<char>&)’          return std::to_string(val);                 ~~~~~~~~~~~~~~^~~~~ 

But I can't get how to resolve it. I tried to check type manually but error is in compile time,so it didn't help


You could just provide a new overload for to_string

std::string to_string(const std::string& s) { return s; } 

You could put the code above inside the class, as a private method, or inside a suitable namespace, so to avoid possible clashes when, say, somebody uses your code and wishes to write her/his own overload of to_string.

EDIT: As noted in the comments below, you cannot put such an overload in the std namespace, as a new declaration of std::to_string is forbidden, see Extending the namespace std.

EDIT: If you need to possibly call std::to_string, you may need to add an additional to_string template function to your code as

template <typename T> typename std::enable_if<!std::is_convertible<T, std::string>::value, std::string>::type to_string(T r) const { return std::to_string(r); } 

(Do not forget #include <type_traits> for that).

This is because, even if you import the standard library std::to_string by using namespace std, the member function to_string will have the priority. See the discussion: C++: Why member function has priority over global function. Here you can see a minimal example.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: