I have the following MWE:
#include <iostream>
#include <memory>
class A {
public:
int n = 42;
typedef std::shared_ptr<A> Ptr;
};
template<typename T>
void foo(typename T::Ptr arg) {
std::cout << arg->n << std::endl;
}
template<typename T>
void bar(T arg) {
std::cout << arg.n << std::endl;
}
int main() {
A::Ptr a = A::Ptr(new A());
foo<A>(a); // Can I avoid giving <A> here explicitly.
// foo(a); // does not compile
bar(*a); // after all this does work
return 0;
}
To me it looks like it should also be possible to call foo(a)
instead of foo<A>(a)
. Why is this not possible and can I somehow change the definition of foo
to make this possible?
I realize that I could just skip the ::Ptr
in the signature, but I still want to have access to the A
type without the pointer.
That is not possible because that is non-deducible context.
The type of a
is just std::shared_ptr<A>
, which means if foo(a)
works, then the following should also work:
std::shared_ptr<A> x(new A());
foo(x);
If so, then what should T
be deduced to — and why? You might be tempted to say "T
should be deduced to A
, because A
has a nested type Ptr
which is same as std::shared_ptr<A>
". Well, what if there is another class defined as:
struct B
{
typedef std::shared_ptr<A> Ptr;
};
What should T
be deduced to? A
or B
? or something else?
Here is another topic that discusses non-deducible context using a different example:
Hope that helps.
Nawaz's answer has explained why the code doesn't work, I'll focus on this question:
but I still want to have access to the
A
type without the pointer.
std::shared_ptr
has a member type element_type
, you could use it like typename T::element_type
. And if you want the code works well with raw pointer too, you could provide a trait class template:
template <typename T>
struct trait_element_type {
using element_type = std::remove_pointer_t<T>;
};
template <typename T>
struct trait_element_type<std::shared_ptr<T>> {
using element_type = T;
};
And then use it as:
template<typename T>
void foo(T arg) {
std::cout << arg->n << std::endl;
typename trait_element_type<T>::element_type x; // retrieve the element type
std::cout << x.n << std::endl;
}
LIVE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With