Make a C++ overloaded operator a function pointer - c++

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);
}

Related

Assigning to struct member using structType*&

I am ok with pointers, but am confused when dealing with test*& t in this program. My understanding, which may be incorrect, is that t contains the address of root and root itself is a pointer to an undeclared(?) struct of type test. I understand what the error means. I am essentially saying 0="abc", but I am unsure of the proper way to assign a new value to root.detailText through t by using the read function. I cant change anything outside the body of the read function.
test.cpp The file where I get the error.
void test::read (istream& in, test*& t)
{
cout<<"test "<<&t->detailText<<" test";
if (&t->detailText == 0){ // Works fine.
&t->detailText = "abc"; //error: lvalue required as left operand of assignment
}
}
test.h
struct test {
std::string detailText;
test* ifYes;
test* ifNo;
test (std::string q, test* yes = NULL, test* no = NULL)
: detailText(q), ifYes(yes), ifNo(no)
{}
static void read (std::istream& in, test*& t);
static void write (std::ostream& out, const test* root);
private:
friend std::istream& operator>> (std::istream&, test*&);
friend std::ostream& operator<< (std::ostream&, const test*);
};
inline
std::istream& operator>> (std::istream& in, test*& n)
{
test::read (in, n);
return in;
}
Other file that begins the read process
test* root = 0;
{
ifstream in (fileName);
if (in.good())
in >> root;
}
... when dealing with test*& t in this program. My understanding, which may be incorrect, is that t contains the address of root and root itself is a pointer to an undeclared(?) struct of type test ...
root itself is a test*, that's correct. But t is a reference to root, not the address of root. So you should use t just as you would use root, and be aware that modifying t will modify root.
So in your function you shouldn't be using & at all. You just need:
void test::read (istream& in, test*& t)
{
if (t != nullptr) {
cout<<"test "<< t->detailText << " test";
t->detailText = "abc";
}
}
Note that you should be checking if t is a valid pointer, before dereferencing it to look at detailText.
Confusion regarding types is a common problem when learning C++. I find it easier to read from right to left.
Given
test*& t
if you read from right to left, it would read as
t is a reference to a pointer to a test object.

C++ Operator>> Overloading with Mutator?

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.

Declaring = and [] operators for a class on the header file, "must be a nonstatic member function" error

I've made a class Block and a struct coords and while implementing the operators i came up with the errors:
'coords operator[](const Block&, const size_t&)' must be a nonstatic member function
'bool operator=(Block&, const Block&)' must be a nonstatic member function
I've declared these 2 in the header file of the class Block as follows:
class Block
{
friend Block operator+(const Block&, const coords&);
friend Block operator+(const Block&, const Block&);
friend coords operator[](const Block&, const std::size_t&);
friend void operator+=(Block&, const coords&);
friend void operator+=(Block&, const Block&);
friend bool operator=(Block&, const Block&);
//...
};
Only the operators [] and = get this error, and I'm not sure why.
I've tried to change the return value and parameter types but it keeps getting the same problem.
Are these two operators special? Or is there an error on my declarations?
I've searched for ways to solve this problem, but couldn't find a suitable answer.
Thank you for the replies.
Not all operators can be overloaded using non-member functions. [] and = are two such operators. They can be overloaded only as member functions.
See http://en.cppreference.com/w/cpp/language/operators for more details.
Those operators cannot be declared as friends. Instead you should declare like this:
coords operator[](const std::size_t&);
bool operator=(const Block&);
Your operators are also not really following conventions. Operators += and = should be returning a Block& namely *this.
The reason is exactly what the error message says: those two have to be non-static member functions. Get rid of the friend from in front of them and remove the first argument.
Further, operator+= is usually implemented as a member function, too, although it doesn't have to be. But if it is, it gives you an easy way to implement operator+ without making it a friend.
#R Sahu's link was useful, showing that [] and = can no be declared as non-member, but it didn't really explain why.
#Baum mit aguen's link cleared some other questions too.
(Thanks for the information)
So, I adjusted my code to this new information as follows:
Block.h
class Block
{
public:
//...
coords* operator[](size_t);
Block operator=(Block);
//...
};
Block.cpp
//...
coords* Block::operator[](size_t index)
{
if(index >= 0 && index < block.size())
return &block.at(index);
coords *tmp = new coords(-1, -1);
return tmp;
}
Block Block::operator=(Block b2)
{
block.empty();
block.reserve(b2.block.size());
append(b2.block);
return *this;
}
//...
This way you can call *(*b1)[0] = c1; being Block* b1 and coords c1.
The friend modifier is useful for other types of implementations, although I only realized after that the implementation of inline had to be done in the header file, not on the cpp.
Block.h
class Block
{
public:
//...
friend std::ostream& operator<<(std::ostream&, const Block&);
friend std::ostream& operator<<(std::ostream&, Block&);
//...
};
inline std::ostream& operator<<(std::ostream& out, const Block& b)
{
// do something
return out;
};
inline std::ostream& operator<<(std::ostream& out, Block& b)
{
// do something
return out;
};
In this case, you need to pass the "this" parameter has to be passed to the function also as these are non-member functions and should be implemented outside the class, in the header file.
I hope this helps, good coding everyone.

Type casting a custom c++ class

If I have my own SString class in c++ and I want to be able to do this:
SString x("text");
LPCSTR p = (LPCSTR)x;
cout<<p;
How do I do it?
Create conversion operator to LPCSTR in your class SString. If you can use C++11 this operator should be explicit.
operator LPCSTR() const { /*return data*/ };
Also you can create some function like (i think this variant is better, than conversion operator)
LPCSTR asLPCSTR() const { /*return data*/ };
In addition to what ForEveR said, note that you can also overload
ostream& operator << (ostream& str, const SString& ss);
and call
cout<<x;
directly.

c++ error : (private data member) was not declared in this scope

Say I have a class like so:
class Ingredient
{
public:
friend istream& operator>>(istream& in, Ingredient& target);
friend ostream& operator<<(ostream& out, Ingredient& data);
private:
Measure myMeas;
MyString myIng;
};
In this overloaded friend function, I'm trying to set the value of myIng
istream& operator>>(istream& in, Ingredient& target)
{
myIng = MyString("hello");
}
In my mind, this should work because I'm setting the value of a private data member of the class Ingredient in a friend function and the friend function should have access to all the private data members right?
But I get this error: ‘myIng’ was not declared in this scope
Any idea on why this is happening?
Because you need to be be explicit that you are accessing a member of the target parameter, not a local or global variable:
istream& operator>>(istream& in, Ingredient& target)
{
target.myIng = MyString("hello"); // accessing a member of target!
return in; // to allow chaining
}
The above will work exactly because the operator is a friend of Ingredient as you mention. Try removing the friendship and you will see that accessing private members will no longer be possible.
Also, as Joe comments: stream operators should return their stream parameter so that you can chain them.
In that scope, there is nothing called myIng. The error is pretty clear on that. Its Ingredient& target who has a myIng member, so you should write:
target.myIng = MyString("hello");