C++ C++;CRTP虚拟功能实例化点
我试图理解一个简单的CRTP模式是否符合标准 下面的代码按照预期编译和工作(在clang上) 但我对相关标准章节/段落的理解是 虚拟函数CRTPC++ C++;CRTP虚拟功能实例化点,c++,templates,crtp,C++,Templates,Crtp,我试图理解一个简单的CRTP模式是否符合标准 下面的代码按照预期编译和工作(在clang上) 但我对相关标准章节/段落的理解是 虚拟函数CRTP:DoSomething()的实例化点 应位于代码的(B)点,其中派生的完整声明不可用。 因此,内部typedef类型也不应可用 有人能指出验证此代码的相关标准章节吗 换句话说,在这种情况下,虚拟函数是实例化的 在C点? 提前非常感谢您提供的任何见解 弗朗西斯科 //------------------------- // START CODE #in
//-------------------------
// START CODE
#include <iostream>
struct Type1 {};
struct Type2 {};
struct Base
{
virtual ~Base() {}
virtual void DoSomething() = 0;
};
template< typename T, typename U >
struct CRTP : U
{
virtual void DoSomething() { DoSomething( typename T::Type() ); }
void DoSomething( Type1 ) { std::cout << "1\n"; }
void DoSomething( Type2 ) { std::cout << "2\n"; }
};
// (A) point of inst. of CRTP< Derived, Base > ( 14.7.1.4 ) ??
// (B) point of inst. of CRTP< Derived, Base >::DoSomething() (14.6.4.1.4 ) ??
struct Derived : CRTP< Derived, Base >
{
typedef Type2 Type;
};
// (C)
int main()
{
Base * ptr = new Derived;
ptr->DoSomething();
delete ptr;
}
// END CODE
//-------------------------
//-------------------------
//起始代码
#包括
结构类型1{};
结构类型2{};
结构基
{
虚拟~Base(){}
虚空DoSomething()=0;
};
模板
结构CRTP:U
{
虚拟void DoSomething(){DoSomething(typename T::Type());}
void DoSomething(Type1){std::cout::DoSomething()(14.6.4.1.4)??
结构派生:CRTP<派生,基>
{
typedef Type2型;
};
//(C)
int main()
{
Base*ptr=新导出的;
ptr->DoSomething();
删除ptr;
}
//结束代码
//-------------------------
相关(?)标准段落:
14.6.4.1
4如果虚拟函数是隐式实例化的,则其实例化点紧跟在其封闭类模板专用化的实例化点之后
14.7.1
4如果类类型在需要完全定义的对象类型的上下文中使用,或者如果类类型的完整性可能会影响程序的语义,则隐式实例化类模板专门化
14.7.1
9实现不应隐式实例化不需要实例化的函数模板、成员模板、非虚拟成员函数、成员类或类模板的静态数据成员。如果否则不会实例化虚拟成员函数
使用
new-Derived
会导致实例化Derived
类
更正:Derived
本身并不是一个模板,因此它的结构布局和包含的成员声明需要立即进行。这导致CRTP
在派生定义之后立即实例化。我以后有更多时间时必须查找正式标准;但问题仍然是insCRTP的转换只指出结构和可用成员,而不是成员函数的主体;当它这样做时,它知道派生类的结构和成员
成员函数在使用之前不会实例化(这里是构造函数),并且它当时已经有了类本身。另一件要查找的事情是,派生的构造函数(因为它不是模板)是紧跟在类之后生成的,还是仅在需要时生成的。如果是前者,则可以通过使用伪参数生成派生的模板来使其变懒。但这并不影响此特定任务函数实例化:无论是在Derived
之后还是在main
之后,函数实例化都不会在解析Derived
的声明之前进行
这将导致CRTP
被实例化。但在这两种情况下,只需要类结构,而不是任何成员的实际代码。删除所有内联函数体,此时您将看到没有问题
现在使用了派生的默认构造函数,因此隐式实例化了Derived::Derived()
。实例化点紧跟在main
的定义之后
在实例化Derived::Derived()
时,它需要CRTP::CRTP()
。它在需要它的模板实例化的同一点实例化。该构造函数需要所有虚拟函数,因此DoSomething()
再次在启动它的实例化的同一点进行实例化。您可以看到,在完全呈现的派生类的完整定义已知之后,所有这些都会发生,即所有成员(而不是函数体)的所有声明
这就是缺少的细节:类定义不包括成员函数定义,即使它们是在类定义的词法封闭区域内给出的。记住定义和声明之间的区别,分别针对类和函数。这似乎是编译器延迟insta按照允许的方式,在翻译单元结束之前停止
CRTP::DoSomething()
(请参阅)
CRTP
在定义派生的之前明确实例化(§14.6.4.1[临时点]/p4,所有引用均为N3936):
对于类模板专门化,类成员模板
专门化,或类成员的专门化
模板,如果专门化是隐式实例化的,因为
如果
从中引用专门化的上下文取决于
模板参数,如果未实例化专门化
在对封闭模板进行实例化之前
实例化紧跟在对象的实例化点之前
封闭模板。否则,此类模板的实例化点
专门化紧跟在命名空间范围声明或
指专业化的定义。
CRTP::DoSomething()
是否需要在