5

次のコンパイル時の「トリック」(ADL に基づく) を使用して、同じ名前空間内のクラスによってのみ有効/定義/呼び出し可能な関数を作成しています。

    namespace Family1
    {
        struct ModelA{};
        struct ModelB{};

        template<typename T>
        bool is_in_Family1(T const& t) 
        {
            return true;
        }
    };

    namespace Family2
    {
        struct ModelC{};

        template<typename T>
        bool is_in_Family2(T const& t) 
        {
            return true;
        }
    };


    Family1::ModelA mA;
    Family2::ModelC mC;

    is_in_Family1(mA);          // VALID
    is_in_Family1(mC);          // ERROR

Foo::Barここで、この原則 (または同様のもの) を使用して、各名前空間に属するクラス (以下)の特殊化を生成したいと思いますFamily1

    // I would like to specialize the method template Bar for classes in Family1 
    // namespace; and another specialization for classes in Family2 namespace
    struct Foo
    {
        template<typename T>
        void Bar( T& _T ){}
    };

保守を容易にし、各名前空間に多数のクラスがあるため、可能であれば、名前空間内のすべてのクラスに名前を付けずにこのチェックを実行したいと考えています。

4

2 に答える 2

1

あなたの「トリック」には1つの大きな問題があります。を呼び出してみると、ADLがとの両方の名前空間を調べるため(の理由で)、その戻りis_in_Family1(make_pair(Family1::ModelA(), Family2::ModelC())値が表示されます。trueModelAModelCpair<ModelA, ModelC>

その問題を無視すると、関数を使用することで簡単にできます。

template<typename T> struct int_ { typedef int type; };

struct Foo
{
    template<typename T, 
             typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
    >
    void Bar( T& t ){}

    template<typename T, 
             typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
    >
    void Bar( T& t ){}
};

それBarは、それがfamily2にあるかfamily1にあるかに応じて呼び出されます。

struct Foo
{
    template<typename T, 
             typename int_<decltype(is_in_Family1(*(T*)0))>::type = 0
    >
    void Bar( T& t, long){}

    template<typename T,
             typename int_<decltype(is_in_Family2(*(T*)0))>::type = 0
    >
    void Bar( T& t, long){}

    template<typename T>
    void Bar( T& t, int) {}

    template<typename T>
    void Bar( T& t ) { return Bar(t, 0); }
};

これには一般的なフォールバックもあります。また、予約名を使用したため、コードの動作は未定義でした。使用しないでください_T

于 2012-01-26T22:24:22.687 に答える
0

これを行うために私が見つけた最も簡単な方法は、Boost Type Traits の is_base_of<> を使用することです

テンプレートの特殊化で継承を使用しようとしましたが、テンプレートの特殊化を使用すると継承が無視され、モデルごとに特化する必要があるため、機能しませんでした。複数のクラスの親に対する部分的な特殊化への回答は、問題を説明しています。

Family1::ModelA と Family::ModelB の Family1:Family1Type および Family2::ModelC のサブクラスを Family2::Family2Type のサブクラスにすると、型特性の使用が機能します。

#include <iostream>
#include <boost/type_traits/is_base_of.hpp>

namespace Family1{

    struct Family1Type{};

    struct ModelA :public Family1Type{};
    struct ModelB :public Family1Type{};

    template<typename T>
    bool is_in_Family1(const T& t){
        return boost::is_base_of<Family1::Family1Type,T>::value;
    }
};

namespace Family2{
    struct Family2Type{};

    struct ModelC :public Family2Type{};

    template<typename T>
    bool is_in_Family2(const T& t){
        return boost::is_base_of<Family2::Family2Type,T>::value;
    }

};

using namespace std;
int main(int argc, char *argv[]) {

    Family1::ModelA mA;
    Family2::ModelC mC;

    std::cout << "mA is in Family1?  " << is_in_Family1(mA) << std::endl;
    std::cout << "mC is in Family2?  " << is_in_Family2(mC) << std::endl;

    //std::cout << "mC is in Family1?  " << is_in_Family1(mC) << std::endl; //ERROR!
    //std::cout << "mA is in Family2?  " << is_in_Family2(mA) << std::endl; //ERROR!

    return 0;
}

これにより、次の出力が得られます。

mA is in Family1?  1
mC is in Family2?  1

Specialization of 'template<class _Tp> struct std::less' in different namespaceによると、別の名前空間で宣言Fooして特化する方法はないと思いますFoo::Bar<>

于 2012-01-25T20:37:45.433 に答える