Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specializing a method template for classes in a namespace

I'm using the following compile-time 'trick' (based on ADL) to create a function that is only valid/defined/callable by classes in the same namespace.

    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

Now, I'd like to use this principle (or something similar) in order to produce a specialization of Foo::Bar (below) for classes belonging to each of the namespaces e.g. 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 ){}
    };

For ease of maintenance and the large number of classes in each namespace, if possible, I'd like to perform this check without naming all the classes in a namespace.

like image 867
Olumide Avatar asked Nov 14 '22 11:11

Olumide


1 Answers

Your "trick" has one big problem. Try calling is_in_Family1(make_pair(Family1::ModelA(), Family2::ModelC()) and you will see that return true, because ADL will look into both the namespaces of ModelA and ModelC (because of pair<ModelA, ModelC>).

Ignoring that problem, with using your functions it is straight forward.

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 ){}
};

That calls Bar depending on whether it is in family2 or 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); }
};

That one has also a generic fallback. And your code had undefined behavior because you used a reserved name. Don't use _T.

like image 69
Johannes Schaub - litb Avatar answered Feb 17 '23 21:02

Johannes Schaub - litb