Templated conversion operator in a template class with default constructor? - c++

I want a templated class with a templated conversion operator and a default constructor, but my initial attempt isn't working.
template<typename T>
class C
{
public:
C() {}
template<typename U>
operator U()
{
C<U> c; // (*)
c._a = dynamic_cast<U*>(_a);
return c;
}
private:
T* _a;
};
But now, when I try to create an instance of C,
template<typename T>
void F()
{
...
C<T> obj;
}
operator U() keeps calling itself over and over at (*), eventually segfaulting. The same thing happens when I define the function that does the casting externally and call it from operator U()--in which case there is no call to C::C() from within the class definition.
It seems to me then that the conversion operator is getting called when I want the default constructor called--it is essentially trying to convert itself. But surely, there's a way to do what I'm trying to do?

Note that in operator X (where X is a type) functions, you should usually return something of type X. You're returning a C<U> when you're trying to convert the invoking object to a U which causes the following to happen:
int a = someC; (where someC is a C of any type) will try to assign a C<X> to an int
operator T<int> will be called on someC which will return a C<int> and then try to assign it to an int
operator T<int> will be called on the aforementioned return value which will return a C<int>
That return value which is a C<int> will attempt to be converted to an int which will call operator T<int>....
goto 3;
Hopefully you can see why the infinite recursion and subsequent stack overflow occurs.
You cannot return a C<U> from operator T<U> of class C. You need to redesign your class if you need to for some reason.

Related

C++ inheritance of operator = [duplicate]

Until a test I've just made, I believed that only Constructors were not inherited in C++. But apparently, the assignment operator= is not too...
What is the reason of that ?
Is there any workaround to inherit the assignment operator ?
Is it also the case for operator+=, operator-=, ... ?
Are all other functions (apart from constructors/operator=) inherited ?
In fact, I encountered this problem as I was doing some CRTP :
template<class Crtp> class Base
{
inline Crtp& operator=(const Base<Crtp>& rhs) {/*SOMETHING*/; return static_cast<Crtp&>(*this);}
};
class Derived1 : public Base<Derived1>
{
};
class Derived2 : public Base<Derived2>
{
};
Is there any solution to get that working ?
EDIT : OK, I have isolated the problem. Why the following isn't working ? How to solve the problem ?
#include <iostream>
#include <type_traits>
// Base class
template<template<typename, unsigned int> class CRTP, typename T, unsigned int N> class Base
{
// Cast to base
public:
inline Base<CRTP, T, N>& operator()()
{
return *this;
}
// Operator =
public:
template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
inline CRTP<T, N>& operator=(const T0& rhs)
{
for (unsigned int i = 0; i < N; ++i) {
_data[i] = rhs;
}
return static_cast<CRTP<T, N>&>(*this);
}
// Data members
protected:
T _data[N];
};
// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
};
// Main
int main()
{
Derived<double, 3> x;
x() = 3; // <- This is OK
x = 3; // <- error: no match for 'operator=' in ' x=3 '
return 0;
}
The assignment operator is technically inherited; however, it is always hidden by an explicitly or implicitly defined assignment operator for the derived class (see comments below).
(13.5.3 Assignment) An assignment operator shall be implemented by a
non-static member function with exactly one parameter. Because a copy
assignment operator operator= is implicitly declared for a a class if
not declared by the user, a base class assignment operator is always
hidden by the copy assignment operator of the derived class.
You can implement a dummy assignment operator which simply forwards the call to the base class operator=, like this:
// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
public:
template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
inline Derived& operator=(const T0& rhs)
{
return Base<Derived, T, N>::operator=(rhs);
}
};
The assignment operator is inherited, sort of, but... In any given
class, if you do not provide a copy assignment operator, the compiler
generates one for you. That means that your derived classes effectively
have an assignment operator:
Derived& operator=( Derived const& );
And the usual hiding rules apply; this hides all of the base class
assignment operators. (If the base class had an assignment operator
with this signature, the derived class would inherit it normally.)
Your assignment operator is technically inherited, but then it's hidden by the default copy assignment operator in the derived class. This default copy assignment then tries to call the base class's copy assignment which doesn't exist since you hid it with your own assignment.
The sanest way to resolve this is to not use operator overloading in non-obvious ways (= not meaning copy assignment for example). In this case, don't use operator=: Call it something like assign or set and then it will inherit and not be hidden by the child copy assignment.
These operators are inherited and there are no compiler versions so they will never be automatically hidden like operator=.
It really is only constructors that aren't inherited, and I can't think of any other compiler-generated functions that could hide something from the parent as in operator=.

passing object dependent comparator as template argument,

I have a class which is similar to following. I am using pairing heap of boost library which needs comparator as template argument. My comparator should access the data and member of class A to make comparisions. Initially, I declared 'my_compare' as struct and overloaded the () operator. But the struct could not access data of class A unless the pointer('this') to class A was passed to it. But that would mean my_compare no longer remains a compile time constant, and it would produce error: 'this' cannot appear in constant expression.
As a second attempt I declared my_compare as a member function (so that it can access the members and data). I get following error now:
error: type/value mismatch at argument 1 in template parameter list for
‘template<class T> struct boost::heap::compare’
I suspect two possible explanations: 'my_compare' is not an (function)object and it is not a binary function as 'this' is implicitely passed. How can I solve this issue.
class A{
public:
//some data(properties)
struct c{
//some data
};
double method1(int variable);
double method2(const struct c&);
bool my_compare(struct c& c, struct c& d){
//accesses member methods and data
}
typedef boost::heap::pairing_heap<struct c, boost::heap::compare<my_compare> > myheap;
}
You need to store an A* inside c. Perhaps like this:
class A{
public:
//some data(properties)
struct c{
//some data
A* owner_A;
c(A* a) : owner_A(a) {}
};
double method1(int variable);
double method2(const struct c&);
static bool my_compare(struct c& c, struct c& d){
//accesses member methods and data
c->owner_A->method1(42);
d->owner_A->method2(d);
}
typedef boost::heap::pairing_heap<struct c, boost::heap::compare<my_compare> > myheap;
}
First things first: The my_compare function either has to be a free-standing function, or made static. There's really no way around it in your situation.
However, if you really need to access members in the A class, then you can make pointer in the c structure to an A instance:
struct c
{
A* a;
// Other members
};
Then when you create a c object you set the a pointer to this.
Than you should use a functor.
class A {
struct my_compare;
friend struct my_compare;
struct my_compare {
A &self;
A(A &self) : self(self) {}
bool operator()(struct c& c, struct c& d) {
// access member data and methods on self
}
};
}
Of course you have to tell it which A instance to use, so you'll have to construct it like my_compare(*this) when constructing the heap.
Note, that you have to make the inner class a friend, it is not automatic. You can either declare it, make it a friend and define it, or you can define it, make it a friend, but than you have to put the operator body outside of the class.

operator= and functions that are not inherited in C++?

Until a test I've just made, I believed that only Constructors were not inherited in C++. But apparently, the assignment operator= is not too...
What is the reason of that ?
Is there any workaround to inherit the assignment operator ?
Is it also the case for operator+=, operator-=, ... ?
Are all other functions (apart from constructors/operator=) inherited ?
In fact, I encountered this problem as I was doing some CRTP :
template<class Crtp> class Base
{
inline Crtp& operator=(const Base<Crtp>& rhs) {/*SOMETHING*/; return static_cast<Crtp&>(*this);}
};
class Derived1 : public Base<Derived1>
{
};
class Derived2 : public Base<Derived2>
{
};
Is there any solution to get that working ?
EDIT : OK, I have isolated the problem. Why the following isn't working ? How to solve the problem ?
#include <iostream>
#include <type_traits>
// Base class
template<template<typename, unsigned int> class CRTP, typename T, unsigned int N> class Base
{
// Cast to base
public:
inline Base<CRTP, T, N>& operator()()
{
return *this;
}
// Operator =
public:
template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
inline CRTP<T, N>& operator=(const T0& rhs)
{
for (unsigned int i = 0; i < N; ++i) {
_data[i] = rhs;
}
return static_cast<CRTP<T, N>&>(*this);
}
// Data members
protected:
T _data[N];
};
// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
};
// Main
int main()
{
Derived<double, 3> x;
x() = 3; // <- This is OK
x = 3; // <- error: no match for 'operator=' in ' x=3 '
return 0;
}
The assignment operator is technically inherited; however, it is always hidden by an explicitly or implicitly defined assignment operator for the derived class (see comments below).
(13.5.3 Assignment) An assignment operator shall be implemented by a
non-static member function with exactly one parameter. Because a copy
assignment operator operator= is implicitly declared for a a class if
not declared by the user, a base class assignment operator is always
hidden by the copy assignment operator of the derived class.
You can implement a dummy assignment operator which simply forwards the call to the base class operator=, like this:
// Derived class
template<typename T, unsigned int N> class Derived : public Base<Derived, T, N>
{
public:
template<typename T0, class = typename std::enable_if<std::is_convertible<T0, T>::value>::type>
inline Derived& operator=(const T0& rhs)
{
return Base<Derived, T, N>::operator=(rhs);
}
};
The assignment operator is inherited, sort of, but... In any given
class, if you do not provide a copy assignment operator, the compiler
generates one for you. That means that your derived classes effectively
have an assignment operator:
Derived& operator=( Derived const& );
And the usual hiding rules apply; this hides all of the base class
assignment operators. (If the base class had an assignment operator
with this signature, the derived class would inherit it normally.)
Your assignment operator is technically inherited, but then it's hidden by the default copy assignment operator in the derived class. This default copy assignment then tries to call the base class's copy assignment which doesn't exist since you hid it with your own assignment.
The sanest way to resolve this is to not use operator overloading in non-obvious ways (= not meaning copy assignment for example). In this case, don't use operator=: Call it something like assign or set and then it will inherit and not be hidden by the child copy assignment.
These operators are inherited and there are no compiler versions so they will never be automatically hidden like operator=.
It really is only constructors that aren't inherited, and I can't think of any other compiler-generated functions that could hide something from the parent as in operator=.

Automatic casting of template object to template pointer in c++

I have a URes class which contains a single pointer to <T>, with indirection operators -> and * overloaded so I can use the instance as a pointer directly.
However I also want to be able to pass my URes instance to functions that normally take the pointer inside the URes instance.
How do I make it so that when my URes instance object is passed to a function it is automatically cast to the pointer it contains?
The same way that you create any outbound conversion: by declaring and defining an operator.
In this case, you want a member operator T*.
Example:
template <typename T>
struct Foo {
operator T*() {
return 0;
}
};
void bar(int* p) {}
int main() {
Foo<int> f;
bar(f);
}
However, I'd recommend avoiding this and implementing a member T* get() instead. It should be an explicit step for a calling scope to obtain a pointer from your object.
You can do that by providing a conversion operator from that class to the pointer-type:
class Foo {
public:
operator int() const { // enables implicit conversion from Foo to int
}
};
Note that such implicit conversion can introduce unexpected behavior.

compare instances of a template type and a concrete type

I guess sometimes while writing a template function you might have also run into cases which you need to compare the template parameter typed instance with a concrete typed instance like this
template<class A> void foo()
{
A* something=new A(); //new A() mightnot exist
if(*something==70000)
{
cout<<"Item 42\n";
}
}
But it's important that template can't be leave out of your current design. How will you change and refactor your function ? I'm thankful you will share your experience in real life applications
In any scenario that may arise like this, as long as your A class has the operator==() method defined for it, and it's implicitly convertible to the concrete type being compared to (i.e., no explicit casts are required), then there are no issues. Otherwise, you'll end up with a compiler error, which is a good thing, as it points out your mistakes at compile-time rather than at run-time.
For instance, imagine your A class is defined as follows:
template<typename T>
class A
{
private:
T b;
public:
A(): b(0) {}
const T& value() const { return b; }
template<typename U>
bool operator==(const U& compare) { return compare.value() == b; }
};
Then as long as:
The comparison U object type has a method called value() that can be called to fetch it's internal private "value"
Whatever type U::value() returns is comparable (and implicitly convertable) to your template T type
you're fine. Otherwise you'll get a compiler error complaining about one of those two points.