This the below program i have written for some test.
class tgsetmap
{
public:
std::map<std::string,std::string> tgsetlist;
void operator<<(const char *str1,const char *str2)
{
tgsetlist.insert( std::map<std::string,std::string>::value_type(str1,str2));
}
};
int main()
{
tgsetmap obj;
obj<<("tgset10","mystring");
obj.tgsetlist.size();
}
This throws a compilation error:
"test.cc", line 10: Error: Illegal number of arguments for tgsetmap::operator<<(const char, const char*).
"test.cc", line 22: Error: The operation "tgsetmap << const char*" is illegal.
2 Error(s) detected.*
Am i wrong some where?
You can't force operator<< to take two arguments on right-hand side. The following code:
obj<<("tgset10","mystring");
does not work as a function call with two arguments but instead just uses the , operator. But it's probably not what you are interested in.
If you need to pass two arguments to the << operator, you need to wrap them in some other (single) type. For example, you could use the standard std::pair, i.e. std::pair<const char*, const char*>.
But note that the operator<< should also return some reasonable type suitable for << chaining. That would probably be a tgsetmap& in your case. The following version should work fine:
#include <map>
#include <string>
#include <iostream>
class tgsetmap
{
public:
typedef std::map<std::string, std::string> list_type;
typedef list_type::value_type item_type;
list_type tgsetlist;
tgsetmap& operator<<(item_type item)
{
tgsetlist.insert(item);
return *this;
}
};
int main()
{
tgsetmap obj;
obj << tgsetmap::item_type("tgset10","mystring")
<< tgsetmap::item_type("tgset20","anotherstring");
std::cout << obj.tgsetlist.size() << std::endl;
}
Note that I've added typedefs to not have to repeat the type names over and over again. I've also made operator<< return a tgsetmap& so that << could be chained (used like in the modified main() above). And finally, I've reused the std::map<...>::value_type to make it simpler but you could also use any other type of your own.
But I believe that you may prefer using a regular method instead. Something like:
void add(const char *str1, const char *str2)
{
tgsetlist.insert( std::map<std::string, std::string>::value_type(str1, str2));
}
(inside the class declaration), and then:
obj.add("tgset10", "mystring");
The operator<< inside of a class must be overloaded like this:
T T::operator <<(const T& b) const;
If you want to overload it with 2 arguments, you can do it outside of a class:
T operator <<(const T& a, const T& b);
My compiler, for example, gives a more detailed error message for the code you posted:
If you are not sure about an operator overloading syntax, there is a wiki article about it.
Yes. operator << is binary operator. not ternary. not forget about this pointer.
As mentioned, the << is binary operator, so there is no way it can take more than two args(One should be this if you are declaring inside the class or a LHS if you are declaring outside the class). However you can accomplish the same functionality by doing obj<<"tgset10". <<"mystring";. But since << is a binary operator, you have to do some hack for this.
For this, I ve assigned a static variable op_count, where in I will determine if it is the value or the type. And another static variable temp_str to store the previous value across invocations.
class tgsetmap
{
public:
std::map<std::string,std::string> tgsetlist;
static int op_count = 0;
static const char *temp_str;
tgsetmap& operator<<(const char *str)
{
op_count++;
if (op_count%2 != 0) {
temp_str = str;
}
else {
tgsetlist.insert( std::map<std::string,std::string>::value_type(temp_str,str));
}
return this;
}
};
So you can do
int main()
{
tgsetmap obj;
obj<<"tgset10"<<"mystring";
obj.tgsetlist.size();
}
Or simply you can embed the value and type in the same string using some separator,
value:type = separator is :
value_type = separator is _.
Related
I've got a struct like this:
// Literal.hpp
struct Literal
{
std::variant<
std::nullptr_t,
std::string,
double,
bool
>
value;
friend std::ostream &operator<<(std::ostream &os, Literal &literal);
};
and I'm trying to implement the << operator like this:
// Literal.cpp
Literal::Literal() : value(value) {}
std::ostream &operator<<(std::ostream &os, const Literal &literal)
{
std::visit(/* I don't know what to put here!*/, literal.value);
}
I've tried implementing the operator like this (note: I would take any elegant solution it doesn't have to be a solution to this implementation below)
// In Literal.cpp
std::ostream &operator<<(std::ostream &out, const Literal literal)
{
std::visit(ToString(), literal.value);
return out;
}
struct ToString; // this declaration is in literal.hpp
void ToString::operator()(const std::nullptr_t &literalValue){std::cout << "null";}
void ToString::operator()(const char &literalValue){std::cout << std::string(literalValue);}
void ToString::operator()(const std::string &literalValue){std::cout << literalValue;}
void ToString::operator()(const double &literalValue){std::cout << literalValue;}
void ToString::operator()(const bool &literalValue){std::cout << literalValue;}
But in my main function, passing a char array literal doesn't casts it into a bool when it runs! ignoring the operator overload taking a char:
main() {
Literal myLiteral;
myLiteral.value = "Hello World";
std::cout << myLiteral << std::endl;
}
This is a bug in your standard library. Presumably you're using libstc++ (the GNU C++ standard library), since that's what Godbolt shows as messing up. If you compile with libc++ (Clang/LLVM's C++ standard library), this works as expected. According to std::vector<Types...>::operator=(T&& t)'s cppreference page, it
Determines the alternative type T_j that would be selected by overload resolution for the expression F(std::forward<T>(t)) if there was an overload of imaginary function F(T_i) for every T_i from Types... in scope at the same time, except that:
An overload F(T_i) is only considered if the declaration T_i x[] = { std::forward<T>(t) }; is valid for some invented variable x;
If T_i is (possibly cv-qualified) bool, F(T_i) is only considered if std:remove_cvref_t<T> is also bool.
That last clause is there for this very situation. Because lots of things can convert to bool, but we don't usually intend this conversion, that clause causes conversion sequences that would not normally be selected to be selected (char const* to bool is a standard conversion, but to std::string is "user-defined", which is normally considered "worse"). Your code should set value to its std::string alternative, but your library's implementation of std::variant is broken. There's probably an issue ticket already opened, but if there isn't, this is grounds to open one. If you're stuck with your library, explicitly marking the literal as a std::string should work:
literal.value = std::string("Hello World");
For the elegance question, use an abbreviated template lambda.
std::ostream &operator<<(std::ostream &os, Literal const &literal)
{
std::visit([](auto v) { std::cout << v; }, literal.value);
// or
std::visit([](auto const &v) {
// gets template param vvvvvvvvvvvvvvvvvvvvvvvvv w/o being able to name it
if constexpr(std::is_same_v<std::decay_t<decltype(v)>, std::nullptr_t>) {
std::cout << "null";
} else std::cout << v;
}, literal.value);
// only difference is nullptr_t => "nullptr" vs "null"
return std::cout;
}
Also, your friend declaration doesn't match the definition. Actually, it shouldn't be friended anyway, since it needs no access to private members.
// declaration in header, outside of any class, as a free function
std::ostream &operator<<(std::ostream&, Literal const&);
// was missing const ^^^^^
I have a class called Log, which overload the operator <<:
class Log
{
public:
static void init(std::ostream&);
Log(const std::string&);
~Log(); //Write to the log here
Log& operator<<(bool);
Log& operator<<(const std::string&);
private:
std::stringstream text;
static std::ostream *stream;
std::string tag;
};
Ok, here is the problem, when i write to the log like this:
int main()
{
std::ofstream file;
file.open("log.txt",std::ios::app);
Log::init(file);
Log("[INFO]") << "Test";
file.close();
}
The operator<< which receives a bool is called, that write true to the log..., if i delete the operator implementation which receives a bool then the other one is called correctly.
I think this happens because the char* can be interpreted as bool... but how can i fix it??
Create a third operator<< overload that takes a char * parameter.
I think your analysis of the problem is probably correct, although surprising.
There are two possible << operators, one taking a std::string, and one taking a bool. The first requires a user-defined conversion, constructing a std::string object from a char array. The second requires a standard conversion, converting a pointer to a bool (null pointer becomes false, non-null pointer becomes true). The rule here is that a standard conversion is better than a user-defined conversion (13.3.3.2 [over.ics.rank] /2), so the compiler chooses the bool version.
You may drop all operator << in your class and have a template:
template <typename T>
Log& operator << (Log& log, const T& value) {
// ...
return log;
}
Replace <<(bool) by <<(OnlyBool), with OnlyBool defined as:
struct OnlyBool
{
OnlyBool(bool b) : m_b(b){}
bool m_b;
};
The idea is to use a type that is implicitly created from bool, but only bool.
(Sorry for the terseness, I'm writing this on my phone)
I have a derived basic_ostream class and an inline modifier (similar to setw). My stream class should also inherit all the operator << behavior from its parent. I get different compiler errors depending on whether I use the "using" keyword or not:
#include <iostream>
struct modifier { };
template <typename C, typename T=std::char_traits<C> >
struct mystream : public std::basic_ostream<C, T>
{
// this is where the trouble is
using std::basic_ostream<C, T>::operator <<;
inline mystream & operator << (const modifier & mod)
{
// ...custom behavior...
return *this;
}
};
int main()
{
mystream<char> foo;
modifier m;
foo << "string"; // this fails if the using is present
foo << 123; // this fails if the using is absent
foo << m;
}
When I put the using directive in, the compiler is confused about the "string" output, and if I comment it out, it gets confused about the integer 123 output, in both cases giving me "error: ambiguous overload for 'operator<<'". I have the problem with both g++ 4.2.1 and g++4.8. What's the right way forward here?
Rather then inherit from std::basic_ostream, won't it be sufficient to just re-implement << for your modifier struct using a regular stream:
std::ostream & operator << (std::ostream &stream, const modifier & mod)
{
// ...custom behavior...
return stream;
}
Your solution seems overcomplicated, but I think the actual error you get comes from your overload of << - it has to accept two arguments (first argument being reference to stream itself).
Without the using, it is clear: the compiler will not find any
of the member overloads of <<, because your function hides
them. The << is a member, so without the using, it
disappears. The << is not a member, so it still works.
When you add the using: all of the member overloads are
visible, as if they were members of your class. And
"string" will be converted to a char const*. The overload
that the compiler is trying to resolve is:
operator<<( mystream<char>, char const* ).
Now consider some of the overloads to be considered:
std::ostream& mystream::operator<<( void const* );
std::ostream& mystream::operator<<( bool );
std::ostream& operator<<( std::ostream&, char const* );
For the first argument (foo, a mystream), the first two
functions are both better matches than the third (since they are
an exact match); for the second argument (the string literal),
the third function is a better match. Thus: ambiguous.
More generally, there are several problems with your code.
Fundamentally, you do not add << operators by deriving. As
you see, it doesn't work. Perhaps more significantly, something
like:
foo << 123 << m;
will not work, because foo << 123 returns a std::ostream&,
not a mystream, and there is no << which will work with an
std::ostream& and a modifier. You add << operators by
defining new free functions:
std::ostream&
operator<<( std::ostream& dest, modifier const& other )
{
// ...
return *this;
}
If you need additional data to format, you use xalloc and
iword or pword to get it, e.g. to define a manipulator:
static int Modifier::modIndex = std::ostream::xalloc();
class mod1
{
int myModifier;
public:
mod1( int m ) : myModifier( m ) {}
friend std::ostream& operator<<( std::ostream& dest,
mod1 const& mod )
{
dest.iword( modIndex ) = myModifier;
return *this;
}
};
You then access dest.iword( modIndex ) to get this information
in the output routine.
iword() returns a long&, different for each instance of your
stream (and for each different index you use).
If you need more information, you can use pword instead of
iword—pword returns a reference to a void*. If you
want use it to point to dynamically allocated memory, don't
forget to register a callback to delete it (using
ios_base::register_callback).
I tried implicit conversion, but this doesn't work.
#include <string>
#include <iostream>
struct MyClass
{
operator std::string() { return "bar"; }
};
int
main( int argc, char* argv[] )
{
MyClass x;
std::cout << std::string( "foo" ) + x << std::endl;
return 0;
}
Implicit conversion won't work since string's operator+ is templated and you're deducing the template parameters. This looks like a better explanation of what's happening: https://stackoverflow.com/a/8892794/964135
I would just do a cast or write a non-template operator+.
A stupid solution is to not deduce the types and then it will do the implicit conversion:
std::cout << std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::string( "foo" ), x) << std::endl;
Have you tried overloading the + operator?
std::string operator+(std::string& str, MyClass& x){
return str + "bar"
}
This would be a free function, not part of MyClass. Also, it might be necessary to overload the commutative case as well. You can express it in terms of the above one if it doesnt matter.
To the nice answers given by Karthik T and Pubby regarding overloaded operator+(), I would like to add one point.
Usually you would need to access private members of the MyClass inside the overloaded operator+() code (unlike the return "bar"; as in your presumably stripped down example). In that case, you would need to declare it as a friend. You cannot have the operator+() as a member of MyClass, because the MyClass comes on the left side of the operator +. Refer below sample code.
#include <string>
#include <iostream>
using namespace std;
struct MyClass {
public:
MyClass() : bar("bar") {}
friend string operator+(string& str, MyClass& x);
private:
string bar;
};
string operator+(string& str, MyClass& x) {
return str + x.bar;
}
int main( int argc, char* argv[] )
{
MyClass x;
string foo("foo");
std::cout << foo + x << std::endl;
return 0;
}
I have a class similar to boost::any, in that it is a templated container class. I'd like to have a method to write the contained value to a string. However, if the contained type doesn't provide a stream insertion operator, I'd like my method to return some default tring rather than failing to compile. Below is as close as I've come, and should make it clear as to what I'm trying to do:
namespace W {
namespace hide {
template <typename T>
std::ostream& operator<<(std::ostream& out, const T& t) {
return std::operator<<(out, typeid(T).name());
}
}
template <typename T> struct C {
T t_;
std::string ToString() const {
using namespace hide;
std::ostringstream oss;
oss << t_;
return oss.str();
}
};
}
This works pretty well, with some caveats. For example, if I want to actually provide an overloaded insertion operator for a class, then that operator has to either be in the same namespace as the class, or it has to be in the W namespace for it to be considered.
It also has problems with any type that already has a non-member std::operator<<, e.g. char and std::string. If T is one of those types, then the oss << t_ line above becomes ambiguous. This can be worked around by adding overloads for these types inside the W namespace, for example:
std::ostream& operator << (std::ostream& out, const std::string& s) {
return std::operator <<(out, s);
}
My question is, has anyone found a better method than this? Why do I have to add my own overloads for things like std::string? Is this all supported according to the standard, or am I taking advantage of non-standard behavior? (I am testing with g++ 4.3.3)
Below is some code that I recall seeing a while ago in a compiler construction class. I thought it was particularly clever (if not 'clean') so I held on to it.
From http://www.cs.colorado.edu/~main/a++/tree.h
// If data of type T can be printed with the usual << operator, then
// print<T>(out, p) will interpret *p as a T object and print its
// value to out. Otherwise, a message is printed to out, indicating
// that objects of type T are not printable.
template<typename T> void print(std::ostream& out, const void* p)
{
// The first part of this code sets an enum value, is_printable, to
// be 1 if the data type T can be printed with the usual <<
// operator. Otherwise, is_printable is set to zero. The programming
// technique is based on a note from Herb Sutter at
// http://www.gotw.ca/gotw/071.htm
class object
{
public:
object(T convert) { };
};
char operator << (std::ostream&, const object&);
enum { is_printable = sizeof(std::cout << (*static_cast<T*>(0))) == sizeof(char) ? 0 : 1 };
// Notice that the boolean expression in the if-statement is known at
// compile time, so that only one of the two output statements will be
// compiled into object code.
if (is_printable)
out << *static_cast<const T*>(p);
else
out << "(value of type " << typeid(T).name() << " cannot be printed)";
}
When you construct your container object, hold a pointer to the print function for the variable:
void (*printer)(std::ostream&, const void*);
printer = print<T>;
Then later use the printer() function to display the contained value if possible.
Hope this helps.