C ++ CRTP虚拟函数点的实例化 [英] C++ CRTP virtual function point of instantiation

查看:180
本文介绍了C ++ CRTP虚拟函数点的实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



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

我试图理解一个简单的CRTP模式是否有效。 p>

但是我对相关标准章节的描述是
虚拟函数CRTP的实例化点Derived,Base> :: DoSomething()
应该在代码的点(B),其中Derived的完整声明不可用。
因此,内部typedef类型不应该可用。



任何人都可以指出验证此代码的相关标准章节吗?



换句话说,在这种情况下,虚函数被实例化
ATFER点C?

  // ------------------------- 
//开始代码

#include< iostream>

struct Type1 {};
structType2 {};

struct Base
{
virtual〜Base(){}
virtual void DoSomething()= 0;
};

template<类型名称T,类型名称U>
struct CRTP:U
{
virtual void DoSomething(){DoSomething(typename T :: Type()); }

void DoSomething(Type1){std :: cout< 1 \\\
; }
void DoSomething(Type2){std :: cout< 2 \\\
; }
};

//(A)点的inst。的CRTP Derived,Base> (14.7.1.4)?
//(B)inst of inst。的CRTP Derived,Base> :: DoSomething()(14.6.4.1.4)?

struct派生:CRTP< Derived,Base>
{
typedef Type2类型;
};

//(C)

int main()
{
Base * ptr = new Derived;
ptr-> DoSomething();
delete ptr;
}

// END CODE
// -------------------------

相关(?)标准段落:


14.6.4.1
4如果一个虚拟函数被隐式实例化,它的实例化点紧跟在它的封闭类模板专用化的实例化点之后。



14.7.1
4如果在需要完全定义的对象类型的上下文中使用类类型,或者如果完全定义对象类型的完整性,则类模板特化将被隐式实例化类类型可能影响程序的语义。



14.7.1
9实现不应隐式实例化函数模板,成员模板,虚拟成员函数,成员类或不需要实例化的类模板的静态数据成员。



>

h2_lin>解决方案

这似乎是编译器延迟实例化 CRTP (参见 CWG issue 993 )。



CRTP< Derived,Base> 定义派生(§14.6.4.1[temp.point] / p4,所有报价均为N3936):



< >

对于类模板特化,类成员模板
specialization或类
模板的类成员的特殊化,如果专门化被隐式实例化,因为它
从另一个模板特化中引用,如果引用特化的
上下文取决于
模板参数,并且如果特化不是实例化的,则
在实例化之前封装模板,
实例化的点紧接在
封装模板的实例化点之前。否则,此类
专用化的实例化点紧接在命名空间范围声明之前,或
定义引用专业化。




是否需要实例化 CRTP 取决于在需要成员定义存在的上下文中引用的短语(§14.7.1[temp.inst] / p2)。所有非纯虚函数都是odr使用的(§3.2[basic.def.odr] / p2),并且每个程序应该包含每个非内联函数或在该程序中使用的变量的一个定义 (§3.2[basic.def.odr] / p4);是否计数为在需要成员定义存在的上下文中引用不清楚。



(即使不是必需的实例化),但编译器仍然可以根据§14.7.1[ inst] / p11 - 未指定实现是否隐式实例化类模板的虚拟成员函数,如果虚拟成员函数不会另外实例化。)



如果 CRTP< Derived,Base> :: DoSomething()确实被实例化,则情况由§14.6.4.1[temp.point] / p5涵盖, p8(强调我):


5如果一个虚拟函数被隐式实例化,它的
实例化点立即跟随
实例化它的封闭类模板专用化。



8 功能模板的特殊化类模板的成员函数或静态数据成员的$ b或可能
在翻译单元中有多个实例化点,除了点之外还有
对于在
翻译单元内具有实例化点的任何
这样的专门化,翻译单元的结束也被认为是实例化的
点。
类模板的专业化在
中是一个翻译单元内的最多一个实例化点。任何模板的A
专业化可能在
多个翻译单元中具有实例化点。 如果两个不同的实例化点
根据一个
定义规则(3.2)给予模板专用化不同的意义,则程序是不合格的,不需要诊断
。 strong>


也就是说,它有两个实例化点,一个在 CRTP< Derived,Base> 的实例化点,并且在翻译单元的末尾有一个。在这种情况下,在实例的两个点名称查找 typename T :: Type 将产生不同的结果,所以程序是不成形的,无需诊断。 p>

I'm trying to understand if a simple CRTP pattern is valid by the standard.

The code below compiles and works as expected (on clang).

But my understanding of the relevant standard chapters/paragraphs is that the point of instantiation of the virtual function CRTP< Derived, Base >::DoSomething() should be at point (B) of the code, where the full declaration of Derived is not available. Therefore the inner typedef Type should not be available either.

Can anyone kindly point out the relevant standard chapter that validates this code?

In other words, something that says that in this case the virtual function is instantiated ATFER point C? Thanks a lot in advance for any insight.

Francesco

//-------------------------
// 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
//-------------------------

Relevant (?) standard paragraphs:

14.6.4.1 4 If a virtual function is implicitly instantiated, its point of instantiation is immediately following the point of instantiation of its enclosing class template specialization.

14.7.1 4 A class template specialization is implicitly instantiated if the class type is used in a context that requires a completely-defined object type or if the completeness of the class type might affect the semantics of the program.

14.7.1 9 An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class, or a static data member of a class template that does not require instan- tiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.

解决方案

This appears to be a result of the compiler delaying instantiation of CRTP<Derived, Base>::DoSomething() until the end of the translation unit, as it is allowed to do (see CWG issue 993).

CRTP<Derived, Base> is definitely instantiated right before the definition of Derived (§14.6.4.1 [temp.point]/p4, all quotes are to N3936):

For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template. Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.

Whether CRTP<Derived, Base>::DoSomething() is required to be instantiated at all depends on the meaning of the phrase referenced in a context that requires the member definition to exist (§14.7.1 [temp.inst]/p2). All non-pure virtual functions are odr-used (§3.2 [basic.def.odr]/p2), and "every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program" (§3.2 [basic.def.odr]/p4); whether that counts as "referenced in a context that requires the member definition to exist" is unclear.

(Even if it's not required to be instantiated, however, the compiler is still free to instantiate it per §14.7.1 [temp.inst]/p11 - "It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.".)

If CRTP<Derived, Base>::DoSomething() is indeed instantiated, then the situation is covered by §14.6.4.1 [temp.point]/p5 and p8 (emphasis mine):

5 If a virtual function is implicitly instantiated, its point of instantiation is immediately following the point of instantiation of its enclosing class template specialization.

8 A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation. A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one definition rule (3.2), the program is ill-formed, no diagnostic required.

That is, it has two points of instantiation, one right after CRTP< Derived, Base >'s point of instantiation, and one at the end of the translation unit. In this case, at the two points of instantiations name lookup for typename T::Type would produce different results, so the program is ill-formed, no diagnostic required.

这篇关于C ++ CRTP虚拟函数点的实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆