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
If you don't want to specialize the entire class for std::string
you could use std::enable_if
or if constexpr
(c++17)
auto to_string(val_t val)
-> typename std::enable_if<std::is_same<val_t, std::string>::value, std::string>::type
{
return static_cast<std::string>(val);
}
auto to_string(val_t val)
-> typename std::enable_if<!std::is_same<val_t, std::string>::value, std::string>::type
{
return std::to_string(val);
}
Or the more modern approach, with if constexpr
auto to_string(val_t val)
{
if constexpr (std::is_same<val_t, std::string>::value)
{
return static_cast<std::string>(val);
}
else
{
return std::to_string(val);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With