模板类的嵌套类 - 互操作性和可见性

问题描述 投票:0回答:1

我有一个模板类

A<T>
和一个嵌套类
Inner
- 我用它来隐藏实现细节。我可能有不同的类实例
A
A
可以保存指向
Inner
的指针,我可能需要在 2 个不同的实例中对这些指针进行操作。在这些情况下,我可能会得到 2 个不同的内部类 -
A<T1>::Inner
A<T2>::Inner
。从编译器的角度来看,它们是不同的类型并且不兼容。一个无效的例子:

template<typename T>
class A {
    template <typename T2> friend class A;

    struct Inner {
        Inner(int64_t timestamp) : timestamp(timestamp) {}
        int64_t timestamp;
    };

    Inner* inner_pointer;
    T val;

public:
    template<typename U>
    A(const A<U> other, const T& val) : inner_pointer(other.inner_pointer), val(val) {}

    A(const T& val, int64_t time_now) : inner_pointer(new Inner(time_now)), val(val) {}
};

int main(int argc, char const *argv[]){
    A first('a', 123);
    A second(first, 0.2);
    return 0;
}

解决这个问题的一种方法可能是使用

reinterpret_cast<Inner*>(other.inner_pointer)
,但这很丑陋,我猜也是 UB。

另一种方法是不创建

Inner
和嵌套类,而是创建一个单独的类:

struct Inner {
    Inner(int64_t timestamp) : timestamp(timestamp) {}
    int64_t timestamp;
};

template<typename T>
class A {
    template <typename T2> friend class A;

    Inner* inner_pointer;
    T val;

public:
    template<typename U>
    A(const A<U> other, const T& val) : inner_pointer(other.inner_pointer), val(val) {}

    A(const T& val, int64_t time_now) : inner_pointer(new Inner(time_now)), val(val) {}
};

这解决了问题,但它使

Inner
类对使用
A
类的任何人都可见,因为它是需要包含的头文件的一部分,并且还会污染范围。

我猜 STL 实现使用保留的名称(以下划线开头)来解决这个问题。有没有一种简单/优雅的方法可以在不暴露

Inner
类的情况下实现此目的?

c++ class templates types instantiation
1个回答
0
投票

这是一个基于

A<void>
不是有效实例化假设的技巧。 (如果这是简化的产物,还有其他方法可以获得类似的效果。)

首先,声明(而不是定义)您的模板,并将

A<void>
Inner
定义为嵌套类型。

#include <cstdint>

template<typename T>
class A;

template<>
class A<void> {
    template <typename T2> friend class A;

    struct Inner {
        Inner(int64_t timestamp) : timestamp(timestamp) {}
        int64_t timestamp;
    };

    // Private constructor prevents the use outside the A template.
    A() = default;
    // Protected (or private) destructor allows safe polymorphism without virtual functions.
    ~A() = default;
};

接下来,使用

A<void>
作为基本类型定义通用模板。

template<typename T>
class A : private A<void> {
    template <typename T2> friend class A;

    Inner* inner_pointer;
    T val;

public:
    template<typename U>
    A(const A<U> other, const T& val) : inner_pointer(other.inner_pointer), val(val) {}

    A(const T& val, int64_t time_now) : inner_pointer(new Inner(time_now)), val(val) {}
};

所有模板实例现在都使用相同的

Inner
类型。

这样做的缺点是我们并没有真正改变问题;任何使用

A<void>
模板的人都可以看到
A
类型。然而,它不可用(因为一切都是私有的),并且我们已经消除了命名空间污染,因为没有引入新的标识符。

© www.soinside.com 2019 - 2024. All rights reserved.