2012-01-13 13 views
2

は考える:C++:ポインタ型を指定すると、どのようにpointee型を回復できますか?

struct Field 
{ 
    template<class T> T Value() const 
    { 
    // ??? 
    } 
    template<class S> S SimpleValue() const 
    { 
    return *reinterpret_cast<const S *>(GetVoidPointerToTheActualValue()); 
    } 
    template<class P> const P *PointerValue() const 
    { 
    return reinterpret_cast<const P *>(GetVoidPointerToTheActualValue()); 
    } 
}; 

コンパイラが自動的にディスパッチするように私は、Field::Value<T>()メソッドを実装するにはどうすればよいの:実際にはそうでないP*

  • Field::SimpleValue<S>
  • ある

    • Field::PointerValue<P>T場合さらにそれは保証ですそのTは参照でもポインタへのポインタ型でもありません。

      ありがとうございました。

      EDIT

      @Grizzly - 私は、残念ながらそれはValue<LPCWSTR>()のコンパイル時に失敗し、あなたの提案を試してみました:

      1> playmssqlce.cpp 
      1>c:\dev\internal\playmssqlce\playmssqlce.cpp(75): error C2668: 'sqlserver::Field::Value' : ambiguous call to overloaded function 
      1>   c:\dev\internal\playmssqlce\sqlserverfield.h(19): could be 'std::tr1::enable_if<_Test,_Type> sqlserver::Field::Value<LPCWSTR>(void) const' 
      1>   with 
      1>   [ 
      1>    _Test=false, 
      1>    _Type=LPCWSTR 
      1>   ] 
      1>   c:\dev\internal\playmssqlce\sqlserverfield.h(18): or  'std::tr1::enable_if<_Test,_Type> sqlserver::Field::Value<LPCWSTR>(void) const' 
      1>   with 
      1>   [ 
      1>    _Test=true, 
      1>    _Type=LPCWSTR 
      1>   ] 
      1>   while trying to match the argument list '(void)' 
      

      あなたのアドバイスが右に感じるので、それは、なぜ私には不明です。ところで、私は愚かなミスを修正した後のVisual Studio 2010

      EDIT2

      を使用しています、私はまだ問題を抱えています。だから、ここで私が持っているものです。

      struct Field 
      { 
          template<class T> typename enable_if<is_pointer<T>::value, T>::type Value() const { return PointerValue(); } 
          template<class T> typename enable_if<!is_pointer<T>::value, T>::type Value() const { return SimpleValue(); } 
          template<class T> T SimpleValue() const   { return *reinterpret_cast<const T *>(GetVoidPointerToTheActualValue()); } 
          template<class T> const T *PointerValue() const { return reinterpret_cast<const T *>(GetVoidPointerToTheActualValue()); } 
      }; 
      

      私はf.Value<const wchar_t *>()をコンパイルしようとしているが、これを取得しています:私は今、間違っ

      1> playmssqlce.cpp 
      1>c:\dev\internal\playmssqlce\sqlserverfield.h(18): error C2783: 'const T *sqlserver::Field::PointerValue(void) const' : could not deduce template argument for 'T' 
      1>   c:\dev\internal\playmssqlce\sqlserverfield.h(42) : see declaration of 'sqlserver::Field::PointerValue' 
      1>   c:\dev\internal\playmssqlce\playmssqlce.cpp(75) : see reference to function template instantiation 'const wchar_t *sqlserver::Field::Value<const wchar_t*>(void) const' being compiled 
      

      何をしているのですか?

      ありがとうございました。

      EDIT3

      愚かな私。グリズリーによる変更に気づいた:

      template<class T> typename enable_if<is_pointer<T>::value, T>::type Value() const { return PointerValue<typename std::remove_pointer<T>::type>(); } 
      template<class T> typename enable_if<!is_pointer<T>::value, T>::type Value() const { return SimpleValue<T>(); } 
      

      現在作業中です。

    +2

    :あなたは '忘れなかった:: type'が' 'を<...>をenable_if後

    ここでは、このソリューションの完全なコードはありますか? –

    +0

    ええ、私はやったが、まだ問題がある - アップデートを参照してください。 – mark

    +0

    @mark:さて、あなたは 'Value'関数をどのように呼びますか? – Xeo

    答えて

    3

    あなたはenable_ifを使用することができます:あなたはC++11を持っている場合はもちろんstd::enable_ifstd::is_pointer<T>std::remove_pointer<T>

    struct Field { 
        /*Other methods of Field*/ 
        template<class T> 
        typename std::enable_if<std::is_pointer<T>::value, T>::type Value() const { 
        return this->PointerValue<typename std::remove_pointer<T>::type>(); 
        } 
        template<class T> 
        typename std::enable_if<!std::is_pointer<T>::value, T>::type Value() const { 
        return this->SimpleValue<T>(); 
        } 
    
    }; 
    

    は唯一のフィットネスエクササイズです。あなたはstd::tr1::is_pointerまたはboost::is_pointerのいずれかをboost::enable_if(またはboost::enable_if_c)またはenable_ifの書かれた自己(どちらかの方法についてはhereと書いてください)のいずれかと一緒に使用できます。 remove_pointerstd::tr1::remove_pointerboost::remove_pointerの両方として利用できます。それが何PointerValue()戻っているので、私はそれを書いた方法は、あなたが、Value()const P*を渡す必要があるため

    はしかし、あなたはそれはまだあなたがやりたいことではないかもしれないしたいものに応じて。あなたが P*を渡し、バック const P*を取得したい場合は、次のように変更することができますもう一度

    typename std::enable_if< 
        std::is_pointer<T>::value, typename 
        std::add_const<typename 
         std::remove_pointer<T>::type 
        >::type* 
    >::type Value() const; 
    

    あなたはあなたの関数テンプレートをしたい++ 11

    +0

    'std :: true_type'と' std :: false_type'に内部impl関数をオーバーロードし、 'typename std :: is_pointer :: type()'を渡します。 – Xeo

    +0

    問題があります - 私は私の質問を更新しました。 – mark

    +1

    @mark: 'enable_if'を' typename enable_if :: type'として使用する必要があります。あなたのエラーからは、 'enable_if 'を戻り値の型として使用したと思います。さらに、私は 'enable_if'が' tr1'の一部ではないと思っていました(私は間違っているかもしれません) – Grizzly

    1

    cを持っていない場合std::tr1::add_constまたはboost::add_constを使用しますインスタンス化された引数の型に応じて2つの異なる振る舞いを持つこと。これは、テンプレートの特殊化を必要とします。この場合、すべてのポインタ型を特化したいので、必要なのは部分テンプレートの特殊化です。

    関数テンプレートの部分的特殊化をサポートしていません:ソリューションは、操作を実行するためのヘルパークラステンプレートを使用することです:

    template < typename T > 
    struct getValue 
    { 
        static T apply() { default behavior } 
    }; 
    
    template < typename T> 
    struct getValue< T * > 
    { 
        static T * apply() { behavior for pointer types } 
    }; 
    

    このヘルパークラスを、あなたのメンバ関数テンプレートで使用することができます。ただし、Fieldインスタンスの一部のデータにアクセスする必要があるため、ヘルパークラスに渡す必要があります。

    もう1つの点は、戻り値の型がField::valueであることです。これはテンプレートパラメータによって異なります。正しい戻り値の型を判別するには、Field::valueを宣言するときに取得できるヘルパークラスのtypedefを持つことをお勧めします。編集について

    #include <iostream> 
    
    namespace detail { template < typename T > struct getValue; } 
    
    class Field 
    { 
        public: 
        void * getVoidPointerToTheActualValue() const; 
    
        template< class T > 
        typename detail::getValue<T>::result_type value() const; 
    
        private: 
        void * actualValue_; 
    }; 
    
    namespace detail { 
    
    template < typename T > 
    struct getValue 
    { 
        typedef T result_type; 
    
        static result_type apply(Field const & f) 
        { 
         std::cout << "simpleValue" << '\n'; 
         return *reinterpret_cast< const T * >( 
           f.getVoidPointerToTheActualValue()); 
        } 
    }; 
    
    template < typename T > 
    struct getValue< T * > 
    { 
        typedef T const * result_type; 
    
        static result_type apply(Field const & f) 
        { 
         std::cout << "pointerValue" << '\n'; 
         return reinterpret_cast< const T * >(
           f.getVoidPointerToTheActualValue()); 
        } 
    }; 
    
    } //namespace detail 
    
    
    void * Field::getVoidPointerToTheActualValue() const 
    { 
        return actualValue_; 
    } 
    
    template< class T > 
    typename detail::getValue<T>::result_type Field::value() const 
    { 
        return detail::getValue<T>::apply(*this); 
    } 
    
    
    int main() 
    { 
        Field f; 
        f.value<int>(); //prints "simpleValue" 
        f.value< int * >(); //prints "pointerValue" 
    } 
    
    関連する問題