3

次のようなポインタクラスのサブセットがあります。

template <typename T>
struct Pointer
{
     Pointer();
     Pointer(T *const x);
     Pointer(const Pointer &x);
     template <typename t>
     Pointer(const Pointer<t> &x);

     operator T *() const;
};

最後のコンストラクターの目標はPointer、サブクラスの、または基本的に暗黙的にに変換可能な任意の型を渡すことができるようにすることT *です。この実際のルールは、コンストラクターの定義によってのみ適用され、コンパイラーは宣言だけで実際にそれを理解することはできません。Pointer<Sub>それを削除し、のコンストラクターにを渡そうとすると、パスを通過するPointer<Base>可能性があるにもかかわらず、コンパイルエラーが発生しますoperator T *()

上記の問題を解決しながら、別の問題を作成します。Pointer<UnrelatedClass>一方のオーバーロードがaを取り、もう一方がをとるオーバーロードされた関数があり、それPointer<BaseClass>をで呼び出そうとするとPointer<SubClass>、もちろん、後者のオーバーロードが呼び出されることを意図して、2つのオーバーロードの間にあいまいさが生じます。

助言がありますか?(うまくいけば、私は十分に明確でした)

4

2 に答える 2

6

問題の解決策は SFINAE と呼ばれます (置換の失敗はエラーではありません)。

#include "boost/type_traits/is_convertible.hpp"
#include "boost/utility/enable_if.hpp"

template<typename T>
class Pointer {
   ...
   template<typename U>
   Pointer(const Pointer<U> &x,
      typename boost::enable_if<
         boost::is_convertible<U*,T*>
      >::type* =0)
   : ...
   {
     ...
   }
   ...
};

U* が T* に変換可能な場合、デフォルトで void にenable_ifなる typedef メンバーが含まれます。typeその後、すべてが順調です。U* が T* に変換できない場合、この typedef メンバーが欠落しており、置換は失敗し、コンストラクター テンプレートは無視されます。

これにより、変換とあいまいさの問題が解決されます。

コメントへの応答:is_convertible次のようになります。

typedef char one;         // sizeof == 1  per definition
struct two {char c[2];};  // sizeof != 1

template<typename T, typename U>
class is_convertible {
    static T source();
    static one sink(U);
    static two sink(...);
public:
    static const bool value = sizeof(sink(source()))==1;
};
于 2009-12-13T21:46:29.443 に答える
0

問題のコンストラクターを明示的にするようにしてください。たとえば、次のようになります。

 template <typename t>
 explicit Pointer(const Pointer<t> &x);

および/またはを削除しますoperator T *() const;-これもあいまいさを生み出すと思います。

編集

std::auto_ptrインターフェイスを確認し、自分のものと比較してください。少なくとも彼らはあいまいさを解決しました。

于 2009-12-13T21:42:19.907 に答える