3

メンバーのチェック」では、おそらく基本クラスのC ++ 11バージョンで、C++でも機能する継承されたメンバー関数をチェックするためにSFINAEからC++11バージョンの従来のメンバーチェックタイプ特性を開発しました。 11finalクラスですが、C ++ 11機能(つまり、decltype)も使用します。

template<typename T>
class has_resize_method {
    struct Yes { char unused[1]; };
    struct No { char unused[2]; };
    static_assert(sizeof(Yes) != sizeof(No));

    template<class C>
    static decltype(std::declval<C>().resize(10), Yes()) test(int);
    template<class C>
    static No test(...);
public:
    static const bool value = (sizeof(test<T>(0)) == sizeof(Yes));
};

MSVCは、VS2005以降に名前がfinal付けられた非標準の拡張機能として使用されていますが、VS2010でのみ追加されています。そのため、VS2005と2008では、マークされたクラスが従来の型特性を破り、C++11バージョンを使用できなくなります。sealeddecltypesealed

それで、has_resize_methodVC2005 / 08sealedクラスでも機能するように定式化する方法はありますか?

明らかに、C++11のみの機能を使用してC++11のみの問題()を回避するのと同じように、VSのみの拡張機能を使用してクラスfinalのVS2005/08のみの問題を回避しますがsealed3セットのコンパイラ{C++11、{VS2005、VS2008}、その他すべて}で機能するソリューションがあるとしたら、それはすばらしいことですが、多分多すぎて要求できません:)

4

2 に答える 2

4

私はすべての主要なコンパイラで機能するソリューションを思いつくことができました。残念ながら、MSVCには他のコンパイラのソリューションについて不平を言うため、プリプロセッサチェックがあります。(&C::resize == 0)主な違いは、MSVCがsizeof()内の関数ポインターを受け入れないことと、逆に、GCCがチェックで受け入れないように見えることです。Clangは両方を喜んで受け入れます。

#include <iostream>

class Base  {
public:
    void resize(int, int, int) { }
};

class Derived : public Base {

};

class Unrelated  { };

template<typename T>
class has_resize_method {
    struct Yes { char unused[1]; };
    struct No { char unused[2]; };

#ifdef _MSC_VER
    template <class C>
    static Yes test(char (*)[(&C::resize == 0) + 1]);
#else
    template <class C>
    static Yes test(char (*)[sizeof(&C::resize) + 1]);
#endif
    template<class C>
    static No test(...);
public:
    static const bool value = (sizeof(test<T>(0)) == sizeof(Yes));
};

int main()  {
    std::cout << (has_resize_method<Base>::value ? "Base has method resize" : "Base has NO method resize") << std::endl;
    std::cout << (has_resize_method<Derived>::value ? "Derived has method resize" : "Derived has NO method resize") << std::endl;
    std::cout << (has_resize_method<Unrelated>::value ? "Unrelated has method resize" : "Unrelated has NO method resize") << std::endl;
    return 0;
}

出力:

Base has method resize
Derived has method resize
Unrelated has NO method resize

GCC 4.5.3、GCC 4.3.4、Clang 3.0、Visual C ++ 2008、およびVisual C ++2010でテストされています。VisualC++2005にアクセスできませんが、そこでも機能すると思います。また、Comeau Onlineでコンパイルされますが、そこで正しい出力が生成されることを保証することはできません。

finalクラスと__sealedクラスの両方で機能します。

ただし、メンバー関数だけでなく、一般的なメンバーポインタもチェックすることに注意してください。boost::is_member_function_pointerこの動作が望ましくないかどうかなど、チェックを追加することをお勧めします。同様に、引数/引数タイプ/結果タイプの数のチェックを追加することもできます。ここでも、ブーストは非常に役立ちます。ブースト型分解

于 2012-03-11T13:28:24.983 に答える
2

MSVCには、vs2005以降の特別なステートメント__if_existsがあります。ここにMSDNリンク。これを使用して、メンバー関数名を直接確認できます。そして、署名を確認します。以下は、簡単なfoo検出の例です。

template <typename T, typename U>
int8_t FooCheck( void(T::*)(U) )
{
    return 0;
}

template <typename T>
int16_t FooCheck( void(T::*)(double))
{
    return 0;
}

template <typename T>
int32_t FooCheck(void(T::*)(int))
{
    return 0;
}


template <typename T>
class Detector
{
public:

    __if_exists(T::foo)
    {    
       enum
       {
           value = sizeof(FooCheck(&T::foo))
       };
    }
    __if_not_exists(T::foo)
    {
       enum
       {
           value = 0
       };
   }

};


std::cout << Detector<Class>::value << std::endl;
于 2012-03-10T04:17:39.853 に答える