基于继承关系的模板友谊

时间:2016-07-23 07:43:04

标签: c++ templates c++11 c++14

我不确定这是否可以实现。假设我有两个类模板Foo<T>FooOwner<T>,而FooOwner<T>有一个指向Foo<U>的指针成员,其中U是{{1}的子类}}

我想让T成为FooOwner<T>的朋友,但前提是Foo<U>U的子类。那可能吗?如果没有,是否有足够接近的解决方法?

T

2 个答案:

答案 0 :(得分:1)

我不确定你想要达到什么目的,但类型特质is_base_of也许可以帮助你:

#include <type_traits>

class A {};

class B : A {};

class C {};

int main() 
{
    std::is_base_of<A, B>::value; // true
    std::is_base_of<C, B>::value; // false
}

您可以将其与conditional

一起使用
std::conditional<std::is_base_of<A, B>::value, A, SomethingElse>::type
  // will be A if B is derived from A, or SomethingElse otherwise

enable_if

std::enable_if<std::is_base_of<A, B>::value, A>::type
  // will be defined only if B is derived from A

答案 1 :(得分:1)

看起来FooOwner不是Foo外部接口的一部分,你可以在Foo声明它:

template<typename T>
class Foo {
private:
    template<typename U>  // Constrain U to be a superclass of T?
    friend class FooOwner;

    template< typename U>
    class FooOwner {
    public:
        FooOwner(std::enable_if<std::is_base_of<T, U>::value, U*> uptr) : p(uptr){} // (rough idea) 
    private:
        Foo<U>* p;  // This can point to a object of type Foo<U>
                    // where U is a subclass of T
    };    
};

然后,您可以对FooOwner或FooOwners方法的构造函数使用is base of测试或类似方法(如上所述)。

更重要的是,你可以这样做:

template<typename T>
class Foo {
private:
    template<typename U, typename = std::enable_if<std::is_base_of<T, U>::value>> 
    friend class FooOwner;

    template<typename U, typename = std::enable_if<std::is_base_of<T, U>::value>> 
    class FooOwner {
    private:
        Foo<U>* p;  // This can point to a object of type Foo<U>
                    // where U is a subclass of T
    };    
};

第一个和第二个enable_if都不是严格要求的。您可以完全删除友谊(以及第一次启用if),只有当基础派生关系是正确的时,才允许FooOwner 存在。如果您希望允许该类存在,并且仅允许该友谊,则可以删除第二个启用if。在这种情况下保留虚拟模板类型名称:

template<typename U, typename = T> 
class FooOwner {
   . . . 
};

Live demo

如果您希望将FooOwner保留在Foo的外部,您可以以类似的方式将其设为UT的模板。