Is it possible to access functions of a class template argument outside the template? I tried the following without success:
class A {
public:
void func () { std::cout << ("A called"); }
};
template<class T>
class tClass {
public:
T* operator->() {
return mem;
}
T* operator*() {
return mem;
}
const T* operator->() const {
return mem;
}
const T* operator*() const {
return mem;
}
private:
T* mem;
};
and in main:
tClass<A>* t = new tClass<A>();
t->func();
I get the following compiler error: error: 'class tClass<A>' has no member named 'func'
Doesn't overriding the -> operator return a pointer to the template argument? I'm asking because I've seen a very similar code that was working. I've also seen other answers suggesting using typedef, but I'm not sure how it applies here.
Ignore the fact that the mem object is not initialized now.
Thanks in advance!
This:
tClass<A>* t = new tClass<A>();
t->func();
isn't calling tClass<A>::operator->, it's dereferencing the tClass<A>* itself. And tClass<A> doesn't have a func() member function, hence the error. You would have to either double dereference:
(*t)->func();
Or use a non-pointer to tClass<A>:
tClass<A> t;
t->func();
Side-note, this phrasing:
return a pointer to the template argument
isn't right. The template argument is a type. In this case, A. You're returning a pointer to something which has that type - not the type itself.
You also need to initialize your pointer T* mem!, e.g.
template<class T>
class tClass {
public:
explicit tClass(T *p):mem(p){}
T* operator->() {
return mem;
}
T* operator*() {
return mem;
}
const T* operator->() const {
return mem;
}
const T* operator*() const {
return mem;
}
private:
T* mem;
};
and then
tClass<A> t(new A() );
and then go on.
Related
Is it possible to override the -> operator in template class and return something by reference?
I saw this post: Overloading member access operators ->, .*
And there is an example of overriding -> and return by reference, but I can't get this to work with templates. Here's a small example of what I'm trying to achieve:
#include <iostream>
using namespace std;
class A
{
public:
void do_something()
{
cout << "Hey there";
}
};
template<class T>
class Ref
{
public:
Ref(T* ptr)
{
objPtr = ptr;
}
// this is another alternative, but I don't want to write Get() every time I want to access the object
T& get() { return *objPtr; }
template <class T>
Ref<T>& operator->() const { return *objPtr; }
// doesn't work either
//T& operator->() const { return *objPtr; }
// this works as expected, but I really MUST return by reference
//T* operator->() const { return objPtr; }
private:
T* objPtr;
};
int main()
{
A myObj;
Ref<A> ref(&myObj);
// error C2675: unary '->': 'Ref<A>' does not define this operator or a conversion to a type acceptable to the predefined operator
ref->do_something();
return 0;
}
How can this be done?
If you return a reference, you can't use it in ref->do_something(); which requires a pointer. You'd have to use this cumbersome method:
ref.operator->().do_something();
Instead return a pointer - and make it a T* (or const T*), not a Ref<T>*.
Example:
#include <iostream>
class A {
public:
void do_something() {
std::cout << "Hey there\n";
}
};
template<class T>
class Ref {
public:
Ref(T& ptr) : objPtr(&ptr) {} // taking a T& but storing a pointer
const T* operator->() const { return objPtr; }
T* operator->() { return objPtr; }
private:
T* objPtr;
};
int main() {
A myObj;
Ref<A> ref(myObj);
ref->do_something();
}
template <class T>
class A
{
public:
A(std::shared_ptr<T> p) : p(p)
{
}
T* operator->() const {
return p.get();
}
private:
std::shared_ptr<T> p;
};
class B{
public:
void doSomething() {
}
};
int main()
{
auto x = std::make_shared<B>();
auto y = new A<B>(x);
y->doSomething();
return 0;
}
The way I overloaded the pointer operator -> it should return T* (in this case B*) which would in turn have doSomething but I get
main.cpp:40:4: error: ‘class A’ has no member named ‘doSomething’
y->doSomething();
^~~~~~~~~~~
but in fact -> returns a pointer to B, not A
Notice that the type of y is A<B>* and not A<B>. The operator-> can be overloaded for the objects. Pointers are provided the built-in -> only.
Following should work in your case:
(*y)->doSomething();
On a side note, it's weird to have new for no good reason, when you already using a shared_ptr<> for some other allocation. :-)
This question already has answers here:
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 4 years ago.
I have the following struct:
template<typename T>
struct S {
std::unique_ptr<T> ptr;
};
S<std::string>* s = new S<std::string>();
s->any_method();
How to override operator-> to any_method was called on ptr. To be more precise, I would like to:
The expression s->any_method() "would be translated to" s->ptr->any_method().
First of all,
S* s = new S();
is not right. S is a class template, not a class. You need a template parameter to instantiate an object, such as:
S<int>* s = new S<int>();
Assuming that is fixed first ...
You cannot use s->any_method() when s is a pointer.
You can use s->any_method() when s is object or a reference to an object, if you overload operator->.
Here's a minimal example.
#include <memory>
template<typename T>
struct S {
std::unique_ptr<T> ptr;
T* operator->() { return ptr.get(); }
};
struct foo { void any_method() {} };
int main()
{
S<foo> s;
s->any_method();
}
Simply return a pointer.
template<typename T> struct S {
S(T &&t): ptr(std::make_unique<T>(std::move(t))) {}
S(T const &t): ptr(std::make_unique<T>(t)) {}
T *operator->() { return ptr.get(); }
std::add_const_t<T> const *operator->() { return ptr.get(); }
private:
std::unique_ptr<T> ptr;
};
I am making a class that shares data between several objects using dynamic memory. The relevant parts of the class are shown below.
class StrBlob
{
public:
StrBlob::StrBlob(std::initializer_list<std::string> il) :
data(std::make_shared<std::vector<std::string>>(il)) {}
void push_back(const std::string &t) const { data->push_back(t); }
private:
std::shared_ptr<std::vector<std::string>> dataPtr;
};
I understand that by making push_back a const member function, I am saying that this function will not change the member dataPtr. However, the underlying vector that dataPtr points to is not const, as shown by the below code.
//The result is foo = {"bar", "foobar"}
const StrBlob foo = {"bar"};
foo.push_back("foobar");
Is it possible or even desirable to make the underlying vector const by making the StrBlob object const? Should be something like making dataPtr a pointer to const when the object is const, but I'm not sure how to achieve that.
You can make a thin wrapper around std::shared_ptr (details omitted like ctor etc):
#include <memory>
template< class T > class const_propagated_shared_ptr {
std::shared_ptr<T> m_ptr;
public:
T &operator*() { return m_ptr.operator*(); }
T* operator->() { return m_ptr.operator->(); }
const T &operator*() const { return m_ptr.operator*(); }
const T *operator->() const { return m_ptr.operator->(); }
};
class Foobar {
const_propagated_shared_ptr<int> m_ptr;
public:
void f1() { *m_ptr = 10; }
void f2() const { *m_ptr = 10; } // compile error
};
But as this is implementation detail of the class (Foobar in this case) I am not sure that it worse the effort, as to let modify data by const method or not can be controlled by class designer.
Why if I overload the -> operator in this code
class subobj
{
public:
void get()
{
printf("ea");
}
};
template<typename T> class testPT
{
public:
T* operator->()
{
return ptr;
}
T* ptr;
};
int main()
{
subobj myobj;
testPT<subobj> myclass;
myclass.ptr = &myobj;
myclass->get();
return 0;
}
I get the "ea" string printed?
By using "myclass->", that should just return a T*, a pointer to the object. I should have done something like
myclass->->get()
to actually call the get() routine. Where am I getting wrong?
operator-> is magic. :)
It uses chaining, that means it is called again as long as you don't return a plain pointer. When you return a plain pointer, it does one final call to operator->. When you call operator->
obj->foo;
it translates to:
(obj.operator->())->foo;
except when obj is a plain pointer.
You could even do this:
template<typename T> class testPT2
{
public:
T* operator->()
{
return ptr;
}
T* ptr;
};
template<typename T> class testPT
{
public:
testPT2<T> operator->()
{
testPT2<T> p2;
p2.ptr = ptr;
return p2;
}
T* ptr;
};
and it would still work by effectively applying operator-> three times.