我有一个函数address_of
,它返回一个Pointer
(封装一个shared_ptr
)到它的参数。 address_of
需要同时处理左值和右值,因此address_of
有两个版本:一个接受引用,另一个接受右值引用。由于获取临时地址是Bad Thing™,因此address_of
的右值版本需要执行移动构造,以便Pointer
实际拥有某些内容。实施很简单:
template<class T>
inline Pointer address_of(T& value) {
return Pointer(&value);
}
template<class T>
inline Pointer address_of(T&& value) {
return Pointer(new T(std::move(value)));
}
按预期收取临时作品的地址:
Pointer p = address_of(Derived());
但是当我使用以下代码进行测试时:
Base* object = new Derived();
Pointer p = address_of(*object);
海湾合作委员会抱怨说address_of
的电话不明确:
error: call of overloaded ‘address_of(Base&)’ is ambiguous
note: candidates are: Pointer address_of(T&) [with T = Base]
note: Pointer address_of(T&&) [with T = Base&]
我的印象是,一元*
总是返回一个左值,在这种情况下,甚至不应考虑右值版本。到底发生了什么?
答案 0 :(得分:3)
问题是由参考衰减引起的:(正确的术语是“参考崩溃”)
template < typename T >
void f(T && t) { .... }
int x; f(x); // what is f()?
代码中问题的答案是f()是:
void f(T& && t) { .... }
由于参考衰变而变成了这个:
void f(T& t) { .... }
正如您所料,这当然对于定义为:
的任何内容都不明确template < typename T >
void f(T & t) { .... }
这可能有效(固定版本):
#include <type_traits>
#include <utility>
template < typename T >
struct pointer
{
pointer(T& t) {}
pointer(T&& t) {}
};
template < typename T >
pointer<typename std::remove_reference<T>::type>
address_of(T && t)
{
return pointer<typename std::remove_reference<T>::type>(std::forward<T>(t));
}
int main()
{
int x = 5;
pointer<int> o = address_of(x);
pointer<int> p = address_of(5);
}
原因是这个引用衰减的东西只发生在T上模板化的函数中。在这种情况下你的指针类是,但构造函数实际上不是模板本身,所以T&amp;从来没有T&amp;&amp;版本
第一个版本仍然遇到与您的代码相同的问题,因为address_of只是使用T作为指针的模板参数。我们实际上需要原始类型。