CRTP - 嵌套叶类类型的可见性
CRTP - visibility of the type of a nested leaf class
我想了解是否可以在基本 CRTP 类中使用叶 CRTP 类的嵌套类。下面的示例演示了该问题。
#include <iostream>
using namespace std;
template<class T>
class A
{
protected:
T* asLeaf(void)
{return static_cast<T*>(this);}
T const* asLeaf(void) const
{return static_cast<T const*>(this);}
public:
struct Inner
{int a = 10;};
void dispInner(void) const
{std::cout << asLeaf()->inner.a << std::endl;}
// I would like to use T::Inner in this class, e.g.
// typename T::Inner mvInnerA;
// However, I understand that it is not possible to
// use it in the form that is stated above. Thus,
// I am looking for any possible workarounds.
};
class B: public A<B>
{
public:
struct Inner: public A<B>::Inner
{int b = 20;};
protected:
friend A<B>;
B::Inner inner;
public:
void dispInner(void) const
{
A<B>::dispInner();
std::cout << asLeaf()->inner.b << std::endl;
}
};
int main()
{
B b;
b.dispInner();
return 0;
}
编辑
我想根据我收到的反馈提供几点进一步的评论:
- 我知道我可能没有使用适当的设计实践。特别是,
A
是否应该意识到inner
的存在可能会受到质疑。但是,我想在A
中定义一个B::Inner
类型的对象inner
,而不是在B
中提供inner
的定义并在A
中使用它。 - 我知道我不能转发声明
B
和/或B::Inner
以及无法这样做的原因。因此,从技术上讲,设计问题没有解决方案。但是,我正在寻找一种可行的解决方法。
我已经考虑了几种替代解决方案:
- 可能的可行解决方案之一是不要尝试在
A
中"定义"B::Inner inner
,而是使用A
的成员函数来提供允许修改B::Inner inner
A<B>::Inner
部分的功能。 - 另一种可能的解决方案是显式定义类
A<B>::Inner
和B::Inner
(即不作为嵌套类)。但是,我宁愿避免这种情况,因为根据设计,预计任何不是从A
派生的类都需要与A<B>::Inner
或派生自A<B>::Inner
的类进行交互
我提出的两种解决方案都是可以接受的。但是,我正在寻找任何可行的替代方案。
标准说:
类在类说明符的结束
}
被视为完全定义的对象类型(或完整类型)。
因此,当您将A
专门化为A<B>
时,B
不是一个完全定义的对象。因此,您不能期望能够从A
的定义中访问其成员或类型或任何内容(即使您可以从A
的成员方法的定义中回调派生类,这是完全合法的,而不是 CRTP 习惯用法的目的)。
换句话说,当您执行此操作时:
typename T::Inner mvInnerA
您无法保证T
是一个完全定义的对象,这就是您出现错误的原因。
一些替代方案:
您可以将
mvInnerType
定义为函数而不是类型,并将其用作工厂来创建类型为T::inner
的对象:[static] auto mvInnerA() { return typename T::Inner{}; }
将其用作:
auto foo = A<B>::mvInnerA();
或:
auto foo = obj.mvInnerA();
正确的形式取决于是否将其设为
static
。
请注意,您仍然可以以某种方式使用隐藏类型,即使其名称不可访问:using HiddenType = decltype(A<B>::mvInnerA()); HiddenType foo = A<B>::mvInnerA();
您可以使用模板定义别名声明
mvInnerA
,如下所示:template<typename U = T> using mvInnerA = typename U::Inner;
然后将其用作:
auto foo = A<B>::mvInnerA<>{};
对于类型
。T
(让我说)仅在实例化时通过U
间接使用mvInnerA
,您没有上述问题。为此付出的代价是存在烦人的<>
以及可以将自定义类型传递给mvInnerA
的事实
如何使用 CRTP 模板参数的内部类型受到严重限制。
在类模板定义本身的作用域中不能有任何用处。在实例化模板时,它将需要完全定义类型B
,就像skypjack指出的那样,事实并非如此。但是,您可以在未立即使用类模板实例化的上下文中使用它,类模板主要是A
的成员函数。
虽然不能有B::Inner
的类型别名,但可以有一个类型别名模板
template<class C>
using Inner = typename C::Inner
A
的成员函数可以使用哪些来避免typename B::Inner
的冗长,而是使用Inner<B>
。
- 如何更改唯一指针向量的可见性
- 当指向对象的指针作为参数传递给 std::thread 时,内存可见性
- 限制静态库中符号的可见性 (MSVC/Visual C++)
- 班级成员可见性C++
- 内联模板函数的可见性
- Clang 是否可以在使用可见性属性时生成导入库(不带 __declspec(dllexport))?
- std::mutex 的发布-获取可见性保证是否仅适用于关键部分?
- 符号可见性和 gcc 警告
- C++/libscreen 无法更新可见性
- 在 C++11 线程中,std::mutex 对内存可见性有什么保证?
- C++继承构造函数的可见性
- CRTP - 嵌套叶类类型的可见性
- C++模板 - 实例之间的通用操作和成员可见性
- 放松的订单和线程间可见性
- GCC 6.x警告有关Lambda可见性
- C++ 中的Shared_ptr和内存可见性
- 静态库中的符号可见性和操作
- CRTP和基类定义的类型的可见性
- 在定义可见性方面,该标准对undreded_set的Value类型提出了哪些要求
- CRTP和类型可见性