我有以下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;
}
对我来说,看起来也应该可以拨打foo(a)
而不是foo<A>(a)
。为什么这不可能,我可以以某种方式更改foo
的定义以使其成为可能吗?
我意识到我可以跳过签名中的::Ptr
,但我仍然想要在没有指针的情况下访问A
类型。
答案 0 :(得分:8)
这是不可能的,因为是不可导出的上下文。
a
的类型只是std::shared_ptr<A>
,这意味着如果 foo(a)
有效,那么以下应该也工作:
std::shared_ptr<A> x(new A());
foo(x);
如果是这样,那么T
应该推断出什么?为什么?您可能会想“ T
应推断为A
,因为A
的嵌套类型Ptr
与std::shared_ptr<A>
<相同/ EM>”。那么,如果有另一个类被定义为:
struct B
{
typedef std::shared_ptr<A> Ptr;
};
T
应该推断出什么? A
或B
?或其他什么?
以下是使用其他示例讨论不可导入的上下文的另一个主题:
希望有所帮助。
答案 1 :(得分:4)
Nawaz的回答解释了为什么代码不起作用,我将专注于这个问题:
但我仍然想要在没有指针的情况下访问
A
类型。
std::shared_ptr
的成员类型为element_type
,您可以像typename T::element_type
一样使用它。如果你希望代码也适用于原始指针,你可以提供一个特征类模板:
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;
};
然后将其用作:
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;
}