鉴于GMan在这里炮制的美味邪恶的auto_cast
实用功能,我一直试图弄清楚为什么当我尝试从右值(在 MSVC 10.0 上)时它不能为我编译。auto_cast
这是我正在使用的代码:
template <typename T>
class auto_cast_wrapper : boost::noncopyable
{
public:
template <typename R>
friend auto_cast_wrapper<R> auto_cast(R&& pX);
template <typename U>
operator U() const
{
return static_cast<U>( std::forward<T>(mX) );
}
private:
//error C2440: 'initializing': cannot convert from 'float' to 'float &&'
auto_cast_wrapper(T&& pX) : mX(pX) { }
T&& mX;
};
template <typename R>
auto_cast_wrapper<R> auto_cast(R&& pX)
{
return auto_cast_wrapper<R>( std::forward<R>(pX) );
}
int main()
{
int c = auto_cast( 5.0f ); // from an rvalue
}
尽我所能,我尝试遵循 C++0x 参考折叠规则和此处概述的模板参数推导规则,据我所知,上面给出的代码应该可以工作。
回想一下,在 0x 之前的 C++ 中,不允许对引用进行引用:像 A& & 这样的东西会导致编译错误。相比之下,C++0x 引入了以下引用折叠规则:
- A& & 变成 A&
- A& && 变成 A&
- A&& & 变成 A&
- A&& && 变成 A&&
第二条规则是一个特殊的模板参数推导规则,用于通过对模板参数的右值引用获取参数的函数模板:
template<typename T> void foo(T&&);
在这里,以下规则适用:
- 当 foo 在 A 类型的左值上调用时,T 会解析为 A&,因此,根据上面的引用折叠规则,参数类型实际上变成了 A&。
- 当 foo 在类型 A 的右值上调用时,T 解析为 A,因此参数类型变为 A&&。
现在,当我将鼠标悬停在对 的调用上时auto_cast( 5.0f )
,工具提示正确地将其返回值显示为auto_cast_wrapper<float>
。这意味着编译器正确地遵循了规则 2:
当 foo 在 A 类型的右值上调用时,T 会解析为 A。
所以既然我们有一个auto_cast_wrapper<float>
,构造函数应该实例化一个float&&
。但是错误消息似乎暗示它实例化为float
按值获取。
这是完整的错误消息,再次显示 T=float 正确但 T&& 参数变为 T?
main.cpp(17): error C2440: 'initializing' : cannot convert from 'float' to 'float &&' You cannot bind an lvalue to an rvalue reference main.cpp(17) : while compiling class template member function 'auto_cast_wrapper<T>::auto_cast_wrapper(T &&)' with [ T=float ] main.cpp(33) : see reference to class template instantiation 'auto_cast_wrapper<T>' being compiled with [ T=float ]
有什么想法吗?