I am trying to make a little wrapper class such as
template <typename T>
class EdgeTriggeredState
{
public:
void Tick()
{
oldData = newData;
}
EdgeTriggeredState& operator =(const T& v)
{
newData = v;
return *this;
}
// T& operator = (void)
// {
// return oldData;
// }
// T& operator T()
// {
// return oldData;
// }
private:
T oldData;
T newData;
};
Basically I want to be able to directly assign to a variable of type T the value wrapped by the class. I have tried implementing both an assignment (to type T) operator and a cast operator to type T. I am a bit rusty on my C++ as I have been working solely in C. Is there a way to go about implementing this without creating a named getter method?
When I uncomment the first implementation attempt I get error
"../EdgeTriggeredState.h:19:21: error: ‘T& EdgeTriggeredState::operator=()’ must take exactly one argument"
When I uncomment the second implementation (and comment out the first) I get error:
"../EdgeTriggeredState.h:24:16: error: return type specified for ‘operator T’"
When you write an operator T, the return type is implicit, so your code should look something like:
template <typename T>
class DumbWrapper {
T oldData;
T newData;
public:
DumbWrapper& operator = (const T& val) {
newData = val;
return *this;
}
operator T() {
return oldData;
}
};
[Also note the semicolon at the end, and the fact that the constructor and conversion operator were probably intended to be public.]
Related
I'm unable to recognize the following forms of operator overloading, specifically with the template parameter involved. I found this while reading an article on nullptr. I do not see these forms on cppreference overloading page either.
Can anyone explain these forms of overloading and what they are doing?
Thanks
struct nullptr_t
{
void operator&() const = delete; // Can't take address of nullptr
template<class T>
inline operator T*() const { return 0; }
template<class C, class T>
inline operator T C::*() const { return 0; }
};
nullptr_t nullptr;
Starting simpler:
struct A {
operator int() {return 3;}
};
void function() {
A aobject;
int value = aobject; //uses A::operator int()
//value is now 3
}
operator int is a curious member function that allows the struct to be converted to an int. It's very curious in that it's the only case in C++ that uses the return type in order to resolve which overloaded function to call, including that it can resolve template types.
struct A {
operator int*() {return 0;}
};
void function() {
A aobject;
int* value = aobject; //uses A::operator int()
//value now holds the value 0 (NULL)
}
This is the same thing, but now A can be converted to an int*. It is otherwise self explanatory.
struct A {
template<class T>
operator T*() { return 0; }
};
void function() {
A aobject;
short* value = aobject; //uses A::operator T*<int>()
//value now holds the value 0 (NULL)
}
By making A::operator T*() a template method, we can make our class able to be converted to a pointer to any type. This expands the options for what you can convert to. operator T C::*() { return 0; } is similar, but also allows conversion to pointers to any member of any class, which is very rare and advanced.
I am implementing a type (TParameter) which shall be both a boolean (to indicate if the value is valid) and a data value of arbitrary type.
The idea is that if a method takes a parameter of some type, then I can set it to false, to indicate that the value is invalid.
Like this:
someVariable = 123; // use the value 123
someVariable = false; // mark variable as invalid/to-be-ignored
A simplified version of my code:
template <class T>
class TParameter
{
public:
TParameter()
: m_value(),
m_valid(false)
{}
// assignment operators
TParameter& operator= (const T& value)
{
m_value = value;
m_valid = true;
return *this;
}
TParameter& operator= (bool valid)
{
m_valid = valid;
return *this;
}
private:
T m_value;
bool m_valid;
};
void test()
{
TParameter<int16_t> param;
param = false;
param = int16_t(123);
param = 123;
}
When compiling the code I get the error:
ambiguous overload for ‘operator=’ (operand types are ‘TParameter<short int>’ and ‘int’)
The problem is that integer values can be implicitly cast to a bool, and therefore the last line in test() does not compile.
Is it possible to tell the compiler that TParameter& operator= (bool valid) shall only be used if the parameter is a bool (i.e. disable implicit cast to bool)?
You can make the 1st overload template, then the 2nd overload will be preferred only when being passed a bool (because non-template function is preferred over template under same situation). Otherwise, the template version will be selected because it's an exact match.
template <typename X>
TParameter& operator= (const X& value)
{
m_value = value;
m_valid = true;
return *this;
}
TParameter& operator= (bool valid)
{
m_valid = valid;
return *this;
}
LIVE
BTW: In your code, implicit conversion happens when the operator= being called; int is converted to int16_t and then passed to operator=. In the code above, the implicit conversion happens inside the operator=, i.e. m_value = value;.
I'm trying to get a firm grasp on move and copy constructors and assignments.
I have the following simple templated class:
template<typename T>
class Box {
public:
// Copy constructor
explicit Box(const T& val) {
value = val;
}
// Move constructor
explicit Box(const T&& val) {
value = val;
}
// Set and get value
void set(T val) { value = val; }
T get() { return value; }
// Copy assignment operator
T& operator=(const T& val) {
value = val;
}
// Move assignment operator
T& operator=(const T&& val) {
value = val;
}
private:
T value;
};
Which is used by the following code:
int main() {
Box<int> iBox{ 1 };
int j = 5;
Box<int> jBox{ j };
iBox = jBox;
return 0;
}
I would expect, if my code is correct, that when I step into iBox = jBox, I should step into one of the assignment overloads. Why is this not happening?
You have not declared an assignment operator taking a right-hand operand of type Box, so the compiler has no other option than to use its generated default assignment operator.
You also have no return statements in your assignment operators, by the way.
Maybe you meant to write:
Box& operator=(const Box& other) {
value = other.value;
return *this;
}
Box& operator=(Box&& val) {
value = other.value;
return *this;
}
Notice that an rvalue reference to const would make little sense.
I am learning templates and operator overloading. I have written some code but I am confused... Let me explain...
template <class T>
class tempType
{
public:
T value;
bool locked;
tempType():locked(false)
{
value = 0;
}
T operator=(T val)
{
value=val;
return value;
}
tempType<T> operator=(tempType<T> &val)
{
value=val.value;
return *this;
}
operator T()
{
return value;
}
};
And I did...
int main(void)
{
tempType<int> i;
tempType<bool> b;
tempType<float> f;
i.value = 10;
i = i + f;
return 0;
}
What code I need to write in order to execute
tempType<T> operator=(tempType<T> &val){}
Also, I why operator T() is required?
Unless you implement move semantics, operator= should always take a const & reference to the source value. It should also return a reference to the modified object.
tempType & operator=(T const & val)
{
value=val;
return * this;
}
operator T is an implicit conversion function which allows any tempType object to be treated as an object of its underlying type T. Be careful when specifying implicit conversions that they won't conflict with each other.
An implicit conversion function usually shouldn't make a copy, so you probably want
operator T & ()
{
return value;
}
operator T const & () const
{
return value;
}
Given these, you shouldn't need another overload of operator = because the first overload will simply be adapted by the conversion function to a call such as i = b;.
If a series of conversions will result in the operator=(T const & val) being called, you should avoid also defining operator=(tempType const & val) because the overloads will compete on the basis of which conversion sequence is "better," which can result in a brittle (finicky) interface that may refuse to do seemingly reasonable things.
I think I know all the answers so I might as well post full response.
To override default operator= you should declare it as tempType<T> operator=(const tempType<T> &val){}. Now you need to call the method explicitly via i.operator=(other_i).
If you correct the declaration you can use it like this:
tempType<int> i;
tempType<int> other_i;
i = other_i; // this is what you just defined
The operator T() is called a conversion operator. It is kind of reverse or counter part of the conversion constructor which in your case would be tempType(const &T value).
It is used to convert a class object into a given type. So in your case you would be able to write:
tempType<int> i;
int some_int;
some_int = i; // tempType<int> gets converted into int via `operator int()`
template <class T>
class tempType
{
public:
T value;
bool locked;
tempType() : value(), locked(false)
{
value = 0;
}
//althought legal, returning something different from tempType&
//from an operator= is bad practice
T operator=(T val)
{
value=val;
return value;
}
tempType& operator=(const tempType &val)
{
value=val.value;
return *this;
}
operator T()
{
return value;
}
};
int main(void)
{
tempType<int> a;
tempType<int> b;
a = b;
return 0;
}
in the code, a = b calls the operator.
As for the second question, the operator T() is not needed "by default". In your example, it is used when you write i+f:
i is converted to an int
f is converted to a float
the operation (+) is performed
T tempType<int>::operator=(T val) is called for the assignement
Here's a simplified version of my problem. I have a property class. It has data like has_initalized and such which i removed for this example.
When i call a function which uses T its fine. However T& isnt so i decided to write a T& version of it. But this causes all functions which uses plain T to get a compile error. Why is T& interfering with that? For this example how do i get both functions (Q and W) to work without changing main()?
template <class T>
class Property {
T v;
Property(Property&p) { }
public:
Property() {}
T operator=(T src) { v = src; return v; }
operator T() const { return v; }
operator T&() const{ return v; }
T operator->() { return v; }
};
class A{};
void Q(A s){}
void W(A& s){}
int main(){
Property<A> a;
Q(a);
W(a);
}
There is nothing in the overloading rules of C++ which allows the compiler to choose between operatorT() and operatorT&() in the call to Q. So removing the
operator T() const { return v; }
will also remove the ambiguity. But then you'll have a problem because returning a non const reference to a member in a const function is not possible.
For your Q, you can use both conversion functions. You can make the compiler prefer one over the other by making one non-const.
operator T() const { return v; }
operator T&() { return v; }
Now for Q, the operator T& is taken. This way will also fix the call to W to get a non-const reference. You can also return a const reference from the other
operator T const&() const { return v; }
operator T&() { return v; }
This way will still prefer the second conversion function for Q, but if your object a is const and you initialize a const reference, you won't always require to copy v.