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>{...}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With