雖然B
是一種A
,Foo<B>
是不是一種Foo<A>
。
蘋果是一種水果。一袋蘋果也是一袋水果嗎?不,因爲你可以把梨放在一袋水果中。
在你的情況下,你不能在包裝器中創建任何東西,所以這個參數不起作用。但是C++編譯器不夠聰明,無法解決這個問題。在其他語言如Scala中,您實際上可以完成這項工作。
您可以製作process
模板,但有時您不能使用,例如這是某個班的虛擬功能。
通過一些簡單到中等的手動工作和模板元編程,實際上可以使Foo<Derived>
像Foo<Base>
一樣工作。手動工作將涉及將Foo
拆分爲接口和實現部分。
// Instead of class B : public A, use class B : public DiscoverableBase<A>
// Doesn't cost you anything. Won't work with multiple inheritance, where
// scattered-inheritance or similar technique must be adopted.
#include <cstdlib>
template <typename B>
struct DiscoverableBase : public B
{
typedef B Base;
};
struct Void {};
// This fetches Base member type out of T, or Void if there's none.
// Probably could be simplified a bit.
template <typename T>
class BaseOf
{
typedef char yes;
typedef struct { char a[2]; } no;
template <typename Q, size_t> struct GetBase;
template <typename Q>
struct GetBase<Q, sizeof(no)>
{
typedef Void Base;
};
template <typename Q>
struct GetBase<Q, sizeof(yes)>
{
typedef typename T::Base Base;
};
template <typename C> static yes check(typename C::Base*) ;
template <typename C> static no check(...);
public:
typedef typename GetBase<T, sizeof(check<T>(0))>::Base Base;
};
// This is how you use DiscoverableBase.
class A {};
class B : public DiscoverableBase<A> {};
// Foo is a bit more complicated now.
template<typename T> class Foo;
// The base case, inherited by Foo<X> where X has no discoverable base
template<> class Foo<Void> {};
// This is the Foo interface. Note how it retuns a reference to T now.
template<typename T>
class Foo : public Foo<typename BaseOf<T>::Base>
{
public:
virtual T& get() = 0;
};
// This is the Foo implementation.
template<typename T>
class FooImpl : public Foo<T>
{
T val;
public:
FooImpl(T t) {val = t;}
T& get() {return val;}
};
// the rest is mostly unchanged
void process(Foo<A>*) {/* do something */}
int main()
{
B b; FooImpl<B> foo(b);
process(&foo);
}
使'進程'模板函數是我想要避免的。但是,我似乎是對我的問題最合理的解決方案。謝謝。 – cjbrehmer