10

私のコードでは、テンプレートに指定された型がポインターであるかどうかをテストする必要があります-それがスマートかどうか。ブーストによると、それを行うための信頼できる一般的な方法はありません(ここを参照)-またはありますか?

これまでのところ、私は次のことを確認します。

  • A:Tに変換できますvoid*か?
  • B:方法はTありget()ますか?
  • C:Tというタイプはありelement_typeますか?
  • D:get()戻りelement_type*ますか?

(A || B && C && D)の場合、私の型はある種のポインタでなければならないと結論付けます。

テンプレートは次のとおりです。

template <typename T>
class is_pointer_type
{
    typedef struct { char array[1]; } yes;
    typedef struct { char array[2]; } no;

    template <typename C> static yes test_g(decltype(&C::get));
    template <typename C> static no  test_g(...);

    template <typename C> static yes test_e(typename C::element_type*);
    template <typename C> static no  test_e(...);

    enum {
        has_get          = sizeof(test_g<T>(0)) == sizeof(yes),
        has_element_type = sizeof(test_e<T>(0)) == sizeof(yes)
    };

    template <typename Q, bool OK = false>
    struct get { struct type {}; };

    template <typename Q>
    struct get<Q, true>
    {
        typedef decltype(((Q*)nullptr)->get()) type;
    };

    template <typename Q, bool OK = false>
    struct ptr { struct type {}; };

    template <typename Q>
    struct ptr<Q, true>
    {
        typedef typename Q::element_type* type;
    };

public:
    enum {
        types_ok = std::is_same<
                           typename get<T, has_get>::type,
                           typename ptr<T, has_element_type>::type
                   >::value,
        value    = std::is_convertible<T, void*>::value || types_ok
    };
};

これまでのところ、うまくいくようです。しかし、この推論に何か問題がありますか?不快な驚きに備える必要がありますか?const/はどうvolatileですか?

更新(動機付け):

あなたが私のモチベーションを求めているコメントの中で、彼らは正しいです、私はあなたに1つ借りています。ユースケースはLua-C++バインディングライブラリです。クラスインスタンスをLuaに公開する場合、との任意の組み合わせでtemplate <typename T> push_value(T value)基になる型を推測する必要があります。基になるクラスがすでにバインダーに登録されているかどうかを知る必要があります。UT = U const/volatile/*/&T = some_pointer<U>U

4

1 に答える 1

1

ブーストを使用するか、次のような特殊化を使用してカスタムテンプレートを定義することにより、型がポインターであるかどうかを簡単に確認できます。

template <typename C> static no test_pointer(C);
template <typename C> static yes test_pointer(C*);

しかし、もっと好きなら、void*ソリューションに固執することができます。

スマートポインタをチェックするには、代わりに適切な演算子をチェックすることをお勧めします。型は、operator*とoperator->の両方が定義されている場合にのみスマートポインタと見なすことができると思います。だからあなたはチェックする必要があります

template <typename C> static yes test_deref(decltype(&C::operator*));
template <typename C> static no test_deref(...);
template <typename C> static yes test_arrow(decltype(&C::operator->));
template <typename C> static no test_arrow(...);

両方の結果が「はい」である必要があります。したがって、最終的な式は「通常のポインター||(演算子*があります&&は演算子->)」として計算できます。

ただし、これはスマートポインタ専用のソリューションです。スマートポインター以外のタイプ(他のラッパー、コレクションなど)もLuaに渡したい場合は、まったく別の話であり、その解決策を提案するつもりはありません。

于 2012-05-19T19:03:20.543 に答える