Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ - auto casting to std::string

Tags:

c++

casting

c++11

I have this code

template <typename T>
class KeyValueProperty {
protected:
    T value = T();
    std::string key = "";

public:
    KeyValueProperty(const std::string & key) : key(key) { }

    T & operator = (const T &i) { return value = i; };    

    operator const T & (){ return value; };    
};  


struct T2 {
    KeyValueProperty<std::string> x {"x"};  
    KeyValueProperty<double> y {"y"};   
};

and in main

T2 tx;
tx.x = "hellow";    
tx.y = 10;

std::cout << static_cast<std::string>(tx.x) << ::std::endl;
std::cout << tx.y << ::std::endl;

This is working correctly. However, doing only this

std::cout << tx.x << ::std::endl;

will end up in

error C2679: binary '<<': no operator found which takes a right-hand operand of type 'Test::KeyValueProperty' (or there is no acceptable conversion)

Is it possible to have auto-conversion, or I must manually call casting?

like image 460
Martin Perry Avatar asked May 17 '26 21:05

Martin Perry


2 Answers

The reason t.y works even without a custom operator<< is because there already exists an operator<<(std::ostream&, double), and the compiler can also see that it can make a double out of your class. It does so and we're happy.

However, there is no operator<<(std::ostream&, std::string). If there was, the same logic would apply and we'd still be happy. Instead, there is:

template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>& 
    operator<<(std::basic_ostream<CharT, Traits>& os, 
               const std::basic_string<CharT, Traits, Allocator>& str);

That is, a generic insertion operator for any kind of basic_string.

Although there exist some template arguments that would make this as if it were operator<<(std::ostream&, std::string), the compiler isn't going to try and guess which possible template arguments would allow it to subsequently match a conversion of your class to the result. There are too many combinations, so this isn't permitted.

This is why you had to explicitly turn your object into a std::string (aka std::basic_string<char>) - this removes one layer from the problem and it can do regular old type deduction to make this work.

The right solution is to give your wrapper class an insertion operator, to sidestep this issue.

like image 185
GManNickG Avatar answered May 19 '26 11:05

GManNickG


You must provide an appropriate overload of operator<<, for example:

template<class T>
std::ostream& operator<<(std::ostream& os, KeyValueProperty<T> const& kvp)
{
    return os << T(kvp);
}
like image 45
Richard Hodges Avatar answered May 19 '26 12:05

Richard Hodges



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!