Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;CRTP虚拟功能实例化点_C++_Templates_Crtp - Fatal编程技术网

C++ C++;CRTP虚拟功能实例化点

C++ C++;CRTP虚拟功能实例化点,c++,templates,crtp,C++,Templates,Crtp,我试图理解一个简单的CRTP模式是否符合标准 下面的代码按照预期编译和工作(在clang上) 但我对相关标准章节/段落的理解是 虚拟函数CRTP:DoSomething()的实例化点 应位于代码的(B)点,其中派生的完整声明不可用。 因此,内部typedef类型也不应可用 有人能指出验证此代码的相关标准章节吗 换句话说,在这种情况下,虚拟函数是实例化的 在C点? 提前非常感谢您提供的任何见解 弗朗西斯科 //------------------------- // START CODE #in

我试图理解一个简单的CRTP模式是否符合标准

下面的代码按照预期编译和工作(在clang上)

但我对相关标准章节/段落的理解是 虚拟函数CRTP:DoSomething()的实例化点 应位于代码的(B)点,其中派生的完整声明不可用。 因此,内部typedef类型也不应可用

有人能指出验证此代码的相关标准章节吗

换句话说,在这种情况下,虚拟函数是实例化的 在C点? 提前非常感谢您提供的任何见解

弗朗西斯科

//-------------------------
// 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()
是否需要在