ここで作成された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&& になります
2 番目の規則は、テンプレート引数への右辺値参照によって引数を取る関数テンプレートの特別なテンプレート引数推定規則です。
template<typename T> void foo(T&&);
ここでは、次の規則が適用されます。
- 型 A の左辺値で foo が呼び出されると、T は A& に解決されるため、上記の参照折りたたみルールにより、引数の型は事実上 A& になります。
- 型 A の右辺値で foo が呼び出されると、T は A に解決されるため、引数の型は A&& になります。
への呼び出しにマウスをauto_cast( 5.0f )
合わせると、ツールチップにその戻り値が として正しく表示されるようになりましauto_cast_wrapper<float>
た。これは、コンパイラが規則 2 に正しく従っていることを意味します。
型 A の右辺値で foo が呼び出されると、T は A に解決されます。
したがって、 があるauto_cast_wrapper<float>
ので、コンストラクターはインスタンス化して を取得する必要がありますfloat&&
。float
しかし、エラーメッセージは、インスタンス化してby 値を取ることを暗示しているようです。
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 ]
何かご意見は?