code and private members

I would like to do something like this:

template <typename T>
class Foo
{
...
public:
    void DoSomething()
    {
        compile_time_if (T is ClassA)
        {
            m_T.DoThingOne();
            m_T.DoThingTwo();
        }
        DoSomeFooPrivateThing();
        m_T.DoThingThree();
    }
    T m_T;
};

In this case I know that all valid T implement DoThingThree , but only ClassA implements DoThingOne and DoThingTwo . This is not a duck-typing thing, I do want to only do this extra part for ClassA and I do not want to add these methods to the other possible T s. I can't do casting, because the possible T s are not inherited types.

I know that I can use an external helper template to accommodate this:

template <typename T>
void Foo_DoSomething(T& t)
{
    t.DoThingThree();
}

template <>
void Foo_DoSomething(ClassA& t)
{
    t.DoThingOne();
    t.DoThingTwo();
    t.DoThingThree();
}

template <typename T>
class Foo
{
...
public:
    void DoSomething()
    {
        Foo_DoSomething(m_T);
    }
...
};

However now this external template doesn't have access to private members of Foo (can't call DoSomeFooPrivateThing ), which limits its functionality, and it's exposed publicly to the outside, which isn't pretty. (Making the external method a friend just makes things worse.)

Another seemingly-reasonable option is to implement it internally:

template <typename T>
class Foo
{
...
public:
    void DoSomething()
    {
        DoSomethingImpl(m_T);
    }
...
private:
    template <typename T2>
    void DoSomethingImpl(T2& t)
    {
        DoSomeFooPrivateThing();
        t.DoThingThree();
    }

    template <>
    void DoSomethingImpl(ClassA& t)
    {
        t.DoThingOne();
        t.DoThingTwo();
        DoSomeFooPrivateThing();
        t.DoThingThree();
    }
...
};

But this requires duplicating the outer template type and parameter. This is probably acceptable, but it still feels a bit odd. Sadly it doesn't actually compile (at least not in GCC, as it objects to specialisations inside classes).

Is there a better way to do this?


I think your last option is the best one.

Instead of

template <>
void DoSomethingImpl(ClassA& t)
{
    t.DoThingOne();
    t.DoThingTwo();
    DoSomeFooPrivateThing();
    t.DoThingThree();
}

you can just use (no need for use of template here):

void DoSomethingImpl(ClassA& t)
{
    t.DoThingOne();
    t.DoThingTwo();
    DoSomeFooPrivateThing();
    t.DoThingThree();
}

First solution: As you say,we could do like this:

template <typename T> class Foo{

    public:
    void doSomething(){
        doSomething(std::is_same<T,A>());
    }
    private:
    void doSomething(std::true_type){
        cout<<"A do"<<endl;
    }
    void doSomething(std::false_type){
        cout<<"any other do"<<endl;
    }
};

Second solution: Because template class Foo only has one template parameter,so we can directly make a explicit specialization like this.

template <typename T> class Foo{

    public:
     void doSomething(){
         cout<<"any other do..."<<endl;
     }

};

template<> void Foo<A>::doSomething(){
    cout<<"A do"<<endl;

}

Thrid solution: Maybe not a good way, we could do like this, This way(SFINAE) use C++11 or boost enable_if.When the type is same with A,compiler auto select expected class.

#include <iostream>
using namespace std;
class A {};

template <typename T,typename Enable = void>
class Foo
{
public:

    void DoSomething()
    {
        cout<<"anyother do"<<endl;
    }
private:
    T m_T;
};
template <typename T> class Foo<T, typename enable_if<is_same<T,A>::value>::type >
{
public:
    void DoSomething()
    {
        cout<<"A do"<<endl;
    }
private:
    T m_T;
};

More:

If two Foo have many same things,we can make base class for it like this:

template <typename T> class BaseFoo{
 ...
};

and two template class derived from BaseFoo like this:

    template <typename T,typename Enable = void> 
class Foo:public BaseFoo<T>{...}


    template <typename T> class Foo<T, typename enable_if
<is_same<T,A>::value>::type >:public BaseFoo<T>{...}

I've gotten used to your last solution, so it doesn't look odd to me.
If you prefer you could always do

    void DoSomethingImpl(T&t, std::true_type){...}

and

    void DoSomethingImpl(T&t, std::false_type){...}

and then

    DoSomethingImpl(m_T, std::is_same<T, ClassA>{});

This is functionally equivalent but also allows more complex decision-making if the functionality needs to be expanded.

链接地址: http://www.djcxy.com/p/84248.html

上一篇: 使用LLVM的libc ++时,1个符号来自哪里?

下一篇: 代码和私人成员