C++ Operator>> Overloading with Mutator? - c++

I am trying to figure out a way (if possible) to overload the >> operator to function correctly with a mutator. For example, I want to write:
myClass obj;
cin >> obj.setValue;
and have it correctly set the obj's private value using the available mutator in a single line. I know I can use a temporary variable to store the cin and set the obj value with that, but I'm wondering if there is a more concise method such as this. I'm a novice programmer so this is my futile attempt within myClass:
friend std::istream &operator>>(std::istream &in, void (myClass::*pt)(double newValue)) {
double temp;
in >> temp;
pt(temp);
return in;
}
I know I can simply overload the myClass as a whole to accept:
cin >> myClass;
but this would prevent me from setting different individual values within myClass at different times.
Thanks

cin >> obj.setValue or cin >> &obj.setValue are examples of invalid C++. There's no way of getting a reference/pointer to a member function of a particular instance of a class.
What you could do is instead package the this pointer and a pointer to member function in a small struct, and overload operator>> on that instead:
template <typename T, typename Arg>
struct setter_t
{
T* _this;
void (T::*_ptr)(Arg);
};
template <typename T, typename Arg>
auto setter(T& x, void (T::*ptr)(Arg))
{
return setter_t<T, Arg>{&x, ptr};
}
template <typename T, typename Arg>
std::istream &operator>>(std::istream &in, setter_t<T, Arg> s)
{
Arg temp;
in >> temp;
(s._this->*s._ptr)(temp);
return in;
}
Usage:
myClass obj;
std::cin >> setter(obj, &myClass::setValue);
live wandbox example
Here's a C++17 solution that doesn't unnecessarily store _ptr inside setter_t. Usage:
std::cin >> setter<&myClass::setValue>(obj);
live wandbox example

You could make .setValue() return a non const reference to a Functor (a class that overrides the operator() ), then make that Functor override the
std::istream &operator>>(std::istream &is, MySetterFunctor &x){
double temp;
is >> temp;
x(temp);
return is;
}
The functor would be initialized by obj, receive a pointer to obj and use the actual obj's setter method in its
void operator()(double v){ obj->set_value(v);}
For that extra bit of hackery, you could make setValue a non-const public member so that you can just call it like std::cin >> obj.setValue and also normally do x.setValue(someDouble). You may make obj.set_value a protected member function and make MySetterFunctor a friend class of obj.
class Obj{
public:
friend class MySetterFunctor;
MySetterFunctor setValue;
...
}
Big disclaimer: This is all theoretical talk, I am not sure one would want to do this but I believe it would let you do what you want.

Related

How to call the function that accepts std::istream&

I am a beginner in C++. What is the correct way to call a function that expects std::istream&?
Tried it with read(std::cin);, but I get an error from the compiler.
typedef double Element;
template<typename T>
std::list<T> read(std::istream& i) {
Element input;
std::list<Element> l;
while(i>>input) {
l.push_back(input);
}
return l;
}
This is not related to the std::istream& parameter.
The issue is that the function is a function template that requires an explicit template argument determining the type that is supposed to be read from the stream, e.g.:
read<int>(std::cin)
The error message from the compiler should be telling you something like that as well.
That aside, you are then not using T in the function. Probably you wanted to replace all uses of Element by T and remove the typedef.
you have just a small syntax error:
try this code :
typedef double Element;
class test{
public:
auto read(std::istream& i){
Element input;
std::list<Element> l;
while(i>>input){
l.push_back(input);
}
return l;
}
};
int main(){
test t;
t.read(std::cin);
return 0;
}

(De)serializing an enum class

I am trying to serialize and deserialize (using QDataStream but that is irrelevant here) an enum class variable:
enum class Type : char
{
Trivial,
Complex
};
The serialization is easy:
QDataStream &operator<<(QDataStream &stream, Type type)
{
return stream << static_cast<char>(type);
}
But the deserialization is not:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return stream >> static_cast<char &>(type);
}
Apparently the static_cast of reference to enum class to a reference to its underlying type is not allowed. Furthermore, the "obvious" solution:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return stream >> reinterpret_cast<char &>(type);
}
might actually be illegal and not defined by the standard according to the answer to this question because the equivalent expression return stream >> (*static_cast<char *>(static_cast<void *>(&type))); is declared as illegal there (or rather not defined by the standard). If that was the case I would need to do this:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
char c = 0;
stream >> c;
type = static_cast<Type>(c);
return stream;
}
which is NOT pretty, is 4 lines instead of 1 etc. etc. And seems pretty unnecesasry to me for such a (seemingly) simple thing.
My question: Is the reinterpret_cast or equivalent static_cast via void* really illegal (undefined by standard) when casting a reference to enum class variable to a reference of its underlying type?
You could write a template function that will allow you to write 1 line for each operator>> that you define.
template <class UT, class S, class E> S& DeserializeEnumClassValue(S &s, E &e)
{
UT temp;
s >> temp;
e = static_cast<E>(temp);
return s;
}
And use it like that:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return DeserializeEnumClassValue<char>(stream, value);
}
But this can be improved using std::underlying_type (https://en.cppreference.com/w/cpp/types/underlying_type) as it is possible to get it at compile time.
If you take that approach, then you should also do something similar for operator<< to make maintenance easier.
I get the following solution:
template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type&
operator<<(QDataStream &s, const T &t)
{ return s << static_cast<typename std::underlying_type<T>::type>(t); }
template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type&
operator>>(QDataStream &s, T &t)
{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
Which from github, and get verified in the src.
I feel that people often fall into the trap of language and cannot extricate themselves.If you use your hand to fill in the machine code, there is no problem, if you are not wrong.I mean if you have a hard time to come up with a counter-example,hope for some convenience and can tolerate possible mistakes,just do it.Otherwise, using the most secure method.

Templates and string conversion

I am creating a generic class that plans to read/write from a file.
Ergo I am unsure of what type will be instantiated.
How can I convert a string into some unknown type during the read stage?
IE
template<class T>
void fromString(std::string from, T to) {
to = from;
}
Anyway to do this without specializing for a numerous amount of classes?
The idiomatic way to do so is using something like this:
template<typename T>
void fromString(std::string from, T& to) {
std::istringstream iss(from);
iss >> to;
}
Most of the available standard specializations to parse the string input formats, would be covered by the already available std::istream& operator>>(std::istream&, T&); specializations.
Anyway to do this without specializing for a numerous amount of classes?
No, you still need to have specializations for various classes like
class Foo {
private:
int x;
double y;
public:
std::istream& getFromStream(std::istream& input) {
input >> x;
input >> y;
return input;
}
};
std:istream& operator>>(std::istream& is, Foo& subject) {
return subject.getFromStream(is);
}

Make a C++ overloaded operator a function pointer

Is there a way to overload an operator (specifically, operator >>) as a function pointer and then assign it a function at run-time? I want to be able to look at a file at run-time to ascertain the format of the file, then assign the correct function pointer to the operator to make it work as desired. I would assign the correct function in the constructor, before the operator would be called. I realize there are other (perhaps easier) ways to do the same thing, but I'm wondering if this is possible.
Here's what I tried:
bool Flag; // In global scope - set in main()
class MyClass
{
private:
int data;
friend istream & function1(istream & in, MyClass & c);
friend istream & function2(istream & in, MyClass & c);
public:
MyClass() :data(0) {operator>>=((Flag)?&function1:&function2);}
friend istream& (*operator>>)(istream & in, C & c);
};
// function1 and function2 definitions go here
int main (int argc, char **argv)
{
if (argc > 2)
Flag = ((atoi(argv[1]) > 1) ? 1 : 0);
MyClass mcInstance;
ifstream in(argv[2]);
in >> mcInstance;
return 0;
}
I get an error that looks like this:
error: declaration of ‘operator>>’ as non-function
You can't redefine the meaning of any actual function, including operators, at run-time directly: functions are immutable entities. What you can do, however, is to delegate within the function, including a user-defined operator, to a different function using a pointer to a function. For example:
std::istream&
std::operator>> (std::istream& in, MyClass& object) {
return Flag? function1(in, object): function2(in, object);
}
If you want to delegate through a function pointer, e.g., per object, you could set the function pointer up in your object and delegate through that:
class MyClass {
fried std::istream& operator>> (std::istream&, Myclass&);
std::istream& (*d_inputFunction)(std::istream&, MyClass&);
public:
MyClass(): d_inputFunction(Flag? &function1: &function2) {}
// ...
};
std::istream& operator>> (std::istream& in, MyClass& object) {
return (object.d_inputFunction)(in, object);
}

How would I use the >> and << operators for binary data in C++?

Is there a way to use these operators to input and output binary data? The reason I want to do this is that it makes the code readable.
Ex: infile >> filedecrypter >> metadataparser >> audiodecoder >> effects >> soundplayer;
Just to be clear, are you intending to duplicate the semantics of iostreams? Because it looks like you are proposing something different. In the example you give:
infile >> filedecrypter >> metadataparser >> audiodecoder >> effects >> soundplayer;
In iostreams, the meaning here is to read from infile into filedecrypter until you get to whitespace, and then from infile into metadataparser until more whitespace, and so on.
It looks like you are proposing something different, where metadataparser reads from filedecrypter, audiodecoder from metadataparser, etc. In which case I think the answer to your question needs to be qualified a bit.
Can you use operator >> to express this construct? Probably yes.
Can you use iostreams for this? Probably not.
I suggest you clarify what it means when you say A >> B. Perhaps express it as regular methods rather than operator overloads first, and that may clarify the question.
Indeed that can be done, if the library or your code provides the overloads for operator<< and operator>> for it to work. Simple example on how one could do it:
class transformer {
public:
virtual std::iostream& transform(std::iostream&) = 0;
};
class noise : public transformer {
public:
virtual std::iostream& transform(std::iostream&) {
/* extract, change and put into again */
}
};
class echo : public transformer {
public:
virtual std::iostream& transform(std::iostream&) {
/* extract, change and put into again */
}
};
std::iostream& operator>>(std::iostream& io, transformer& ts) {
return ts.transform(io);
}
int main() {
std::stringstream data;
std::ifstream file("sound.wav");
noise n; echo e;
data << file.rdbuf();
data >> n >> e;
/* pipelined data now ready to be played back */
}
The problem with using a pure std::istream is that you would read, but then you wouldn't have a way to put the transformed data back for the next step in the pipeline. Thus i'm using std::iostream here. This approach doesn't seem to be efficient, as every operator>> call would extract the whole data, and put into again.
To have a more performant way to stream this would be to create an expression template. This means, while operator>> is called, you don't do the transforming yet, but you return expression types that will record the chain of operations within its type:
typedef transform< echo< noise< istream > > > pipeline;
std::ifstream file("file.wav");
pipeline pipe(file);
int byte = pipe.get();
would be an example of such a type. The pipelines' structure is decoded into the type itself. Therefore, no virtual functions are needed anymore in the pipeline. It's not constructed on-demand, but using typedef here, to show the principle. Programming such a system is not easy. So you probably should look into existing systems, like Boost.Iostreams (see below). To give you an idea how it would look like, here is an example i just coded up for you :) :
#include <iostream>
template<typename T>
struct transformer {
int get() {
return static_cast<T*>(this)->read();
}
};
struct echot {
template<typename Chain>
struct chain : transformer< chain<Chain> > {
Chain c;
int read() {
return c.get() + 1;
}
chain(Chain const& c):c(c) { }
};
} echo;
struct noiset {
template<typename Chain>
struct chain : transformer< chain<Chain> > {
Chain c;
int read() {
return c.get() * 2;
}
chain(Chain c):c(c) { }
};
} noise;
template<typename T>
typename T::template chain<std::istream&> operator>>(std::istream& is, T) {
return typename T::template chain<std::istream&>(is);
}
template<typename T, typename U>
typename U::template chain<T> operator>>(T t, U u) {
return typename U::template chain<T>(t);
}
int main() {
std::cout << (std::cin >> echo >> noise).get() << std::endl;
}
Entering 0 yields the ASCII code 48 here, which is added 1, and multiplied by 2, yielding a value of 98, which is also finally output. I think you agree this is not some code a starter would want to write. So maybe look into boost.
Boost has an sophisticated iostreams library, which can do many things. I'm sure you would find something fitting to this. Boost.Iostreams
Sure it can be done. Just define your own operator>> and operator<< so they do "the right thing"...
I would make it so I would have methods in the class, like toStream(ostream& os) and fromStream(istream& ), then define
istream& operator>> (istream& is, T& t)
{
t.fromStream(is);
return t;
}
ostream& operator<< (ostream& os, const T& t)
{
t.toStream(os);
return t;
}
There is no need to use streams to move the data. You can create your own classes to do this. This shows an example. Obviously, the Decrypt and MetaDataParser classes can be abstract base classes with virtual functions to allow various functionality be plugged together.
#include <iostream>
#include <istream>
using namespace std;
class Data2
{
};
class Data3
{
};
class Decrypt
{
};
class MetaDataParser
{
};
Data2& operator>>(istream& in, Decrypt& decrypt)
{
return *new Data2;
}
Data3& operator>>(Data2& d2, MetaDataParser& mdp)
{
return *new Data3;
}
int main()
{
Decrypt decrypt;
MetaDataParser mdp;
cin >> decrypt >> mdp;
}