当在封闭类模板中引用特化时,成员类模板的隐式实例化

2024-04-13

#include <iostream>
template<typename T>
struct A{
    template<typename U>
    struct B{};
    B<T> b;   //#2
};
//#3
int main() {
    A<int> a;  // #1
}

考虑上面的代码,template-id的使用A<int>导致专业化的隐式实例化A<int>。根据以下规则:

温度点#4 https://timsong-cpp.github.io/cppwp/n4659/temp.point#4

对于类模板特化、类成员模板特化或类模板的类成员特化,如果由于从另一个模板专业化中引用该专业化而隐式实例化该专业化,如果引用专业化的上下文依赖于模板参数,并且如果该专业化未在封闭模板的实例化之前实例化,则实例化紧接在封闭模板的实例化点之前. 否则,此类专门化的实例化点立即位于引用该专门化的名称空间范围声明或定义之前。

对于参考的专业#1, the 否则该规则的一部分将适用于它。这意味着,实例化点A<int>应该在#3,这里没有问题。然而,实例化为A<int>将导致专门化的实例化B<int>是其成员。因此,if该规则的一部分将适用于B<int>。我困惑的地方就在这里。根据相关规则,实例化点为B<int>应该紧邻封闭模板的实例化点之前,也就是说,之前的某个地方#3,这里看不懂。如果,仔细想想normal class,定义其类成员只有两种方法,一种是在类定义中定义类成员,另一种是在类定义中声明类成员,然后在某个时候在类定义之外定义类成员其中遵循类定义。

使用普通类更改示例:

struct Normal_A_Int{
   struct Normal_B_Int{};
   Normal_B_Int b;
};
int main(){
  Normal_A_Int a;
}

这意味着,成员类的定义Normal_B_Int由于声明,必须位于封闭类的定义中Normal_B_Int b需要一个完整的类类型。

那么,如何才能让成员类的定义B<int>放置在封闭类定义之前的某个位置A<int>?充其量,定义为B<int>应在定义中A<int>。如何解释第一个示例的 POI?


您提供的报价来自温度点/4 https://timsong-cpp.github.io/cppwp/n4659/temp.point#4情况确实如此:

template<typename T>
struct A {
    template<typename U>
    struct B { };
    B<T> b;
};

// point-of-instantiation for A<int>::B<int>
// point-of-instantiation for A<int>
int main() {
    A<int> a;
}

没有太多律师可做。该标准说这些是实例化点。类模板不是类,直觉也不一定会延续下去。它们既有定义又有实例化。

获取外部类的定义。如果是类,则必须定义成员的类型。如果是类模板,则只需声明成员的类型。您可以降低 B 的定义:

template<typename T>
struct A {
    template<typename U> struct B;
    B<T> b;
};

template<typename T>
template<typename U>
struct A<T>::B { };

您无法使用类来执行此操作(定义中具有“不完整”成员),但可以使用类模板来执行此操作。

那么问题来了,为什么模板的实例化点是A<T>::B<T>之前的A<T>?最终,因为标准是这么说的。但请考虑一下,如果是在之后,则根本无法拥有内部类模板。比如说,如果它在定义之内A<T>,名称查找会出现错误,因为定义之间的名称A和实例化点A<int>将不可见于A<int>::B<int>。所以这实际上是有一定道理的。

也许直觉来自于将定义和实例化点混为一谈:

那么,如何才能将成员类 B 的定义放在封闭类 A 的定义之前呢?

事实并非如此。实例化点控制名称可见性。 TU 中截至该点的所有名称都是可见的。 (这是not的定义。)从这个角度来看,直观上很清楚:A<int>::B<int>应该有一个靠近实例化点的实例化点A<int>(他们应该看到相同的其他名称)。如果有顺序,可能内部应该排在第一位(这样A<int>可以有一个A<int>::B<int>成员)。如果没有顺序,则必须有关于实例化如何交错或交互的语言。

该规则有两个有趣的方面。

一是模板可以专门化。因此,为了完成这个要求,当编译器去实例化时A<int>,它必须首先选择专业化,对其进行足够的处理以知道它有一个成员类模板并且需要实例化它,然后停止一切来实例化A<int>::B<int>第一的。这并不困难,但很微妙。可以说,有一个实例化堆栈。

第二个方面更有趣。您可能会从普通的类直觉中预料到B<T>可以使用以下内容(例如 typedef)A<T>在模板上下文中需要实例化A<T>当它还不存在时A<T>::B<T>正在被实例化。喜欢:

template<typename T>
struct A {
    using type = T;

    template<typename U>
    struct B { using type = typename A<U>::type; };

    B<T> b;
};

这可以吗?

如果实例化点A<int>::B<int>在之前A<int>,我们无法真正形成A<int>::type.

这就是境界CWG287 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287 and P1787 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1787r6.html.

CWG287 提议实例化点应相同(一个不在另一个之前)。此外,它将补充:

如果隐式实例化的类模板特化、类成员特化或类模板的特化引用了包含直接或间接导致实例化的特化引用的类、类模板特化、类成员特化或类模板的特化,则要求类参考的完整性和排序应用于专业化参考的上下文中。

在我的例子中,A<int>::B<int>参考A<int>通过引用直接导致其实例化B<int>,因此类引用的完整性和排序要求(typename A<int>::type)应用于专业化参考(B<int> b)。所以没关系。如果 typedef 低于以下定义也没关系B. But if我们将 typedef 移到成员下方b,它将是格式错误的!微妙的!这具有交错实例化的效果。当我们看到该成员时,我们停止正在做的事情,去实例化A<int>::B<int>,但我们可以使用实例化时的顺序和完整性要求A<int>。实例化点是相同的,因此我们也可以使用 TU 中的相同声明。

CWG287 似乎旨在复制编译器已经做的事情。然而,CWG287 自 2001 年以来一直开放。(另请参阅this https://stackoverflow.com/questions/48227757/curiously-mutually-recurring-class-definitions and this https://stackoverflow.com/questions/45907160/russells-paradox-in-c-templates/45926490.)

P1787似乎是针对C++23的,旨在重写很多微妙的语言。我think旨在达到与 CWG287 类似的效果。但要做到这一点,他们必须彻底重新定义名称查找,我很难知道这一点。 :)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当在封闭类模板中引用特化时,成员类模板的隐式实例化 的相关文章

  • 如何检查图像对象与资源中的图像对象是否相同?

    所以我试图创建一个简单的程序 只需在单击图片框中更改图片即可 我目前只使用两张图片 所以我的图片框单击事件函数的代码 看起来像这样 private void pictureBox1 Click object sender EventArgs
  • 将数组向左或向右旋转一定数量的位置,复杂度为 o(n)

    我想编写一个程序 根据用户的输入 正 gt 负 include
  • 未解决的包含:“cocos2d.h” - Cocos2dx

    当我在 Eclipse 中导入 cocos2dx android 项目时 我的头文件上收到此警告 Unresolved inclusion cocos2d h 为什么是这样 它实际上困扰着我 该项目可以正确编译并运行 但我希望这种情况消失
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 在 Visual Studio 2008 上设置预调试事件

    我想在 Visual Studio 中开始调试程序之前运行一个任务 我每次调试程序时都需要运行此任务 因此构建后事件还不够好 我查看了设置的 调试 选项卡 但没有这样的选项 有什么办法可以做到这一点吗 你唯一可以尝试的 IMO 就是尝试Co
  • WPF TabControl,用C#代码更改TabItem的背景颜色

    嗨 我认为这是一个初学者的问题 我搜索了所有相关问题 但所有这些都由 xaml 回答 但是 我需要的是后台代码 我有一个 TabControl 我需要设置其项目的背景颜色 我需要在选择 取消选择和悬停时为项目设置不同的颜色 非常感谢你的帮助
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 使用 System.Text.Json 即时格式化 JSON 流

    我有一个未缩进的 Json 字符串 例如 hash 123 id 456 我想缩进字符串并将其序列化为 JSON 文件 天真地 我可以使用缩进字符串Newtonsoft如下 using Newtonsoft Json Linq JToken
  • 在 ASP.NET Core 3.1 中使用包含“System.Web.HttpContext”的旧项目

    我们有一些用 Net Framework编写的遗留项目 应该由由ASP NET Core3 1编写的API项目使用 问题是这些遗留项目正在使用 System Web HttpContext 您知道它不再存在于 net core 中 现在我们
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount
  • 为什么我收到“找不到编译动态表达式所需的一种或多种类型。”?

    我有一个已更新的项目 NET 3 5 MVC v2 到 NET 4 0 MVC v3 当我尝试使用或设置时编译出现错误 ViewBag Title财产 找不到编译动态表达式所需的一种或多种类型 您是否缺少对 Microsoft CSharp
  • 如何使用 std::string 将所有出现的一个字符替换为两个字符?

    有没有一种简单的方法来替换所有出现的 in a std string with 转义 a 中的所有斜杠std string 完成此操作的最简单方法可能是boost字符串算法库 http www boost org doc libs 1 46
  • C 中的异或运算符

    在进行按位操作时 我在确定何时使用 XOR 运算符时遇到一些困难 按位与和或非常简单 当您想要屏蔽位时 请使用按位 AND 常见用例是 IP 寻址和子网掩码 当您想要打开位时 请使用包含或 然而 XOR 总是让我明白 我觉得如果在面试中被问
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif

随机推荐

  • 当名称的开头保持相同而结尾不同时,将 CSS 样式应用于 ID 元素

    在 WordPress 中 博客文章的标题通常使用 ID 元素进行格式化 该 ID 元素由永远不会变化的前缀 例如 post 组成 后跟 WordPress 生成的可变数字后缀 对应于唯一的连续帖子编号 每个帖子 在 WordPress 主
  • 根据其中一个字段对元组进行排序

    我的问题与下面的问题相同 但答案很模糊 我不明白如何进行 将 List 从最高到最低排序 https stackoverflow com questions 4017728 sort a listtuple from highest to
  • 将 JSON 数据的 NSString 转换为 NSArray [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我有一个N
  • 多线程和CPU缓存

    我正在使用多个线程在 C 中实现图像过滤操作 并使其尽可能优化 但我有一个问题 如果线程 0 访问内存 并且同时线程 1 访问同一内存 它会从缓存中获取它吗 这个问题源于这两个线程可能运行在 CPU 的两个不同内核中的可能性 因此 另一种说
  • 假设没有非时间指令,“xchg”是否包含“mfence”?

    我已经看过了这个答案 https stackoverflow com a 50279772 391161 and 这个答案 https stackoverflow com a 19099164 391161 但似乎都没有清楚明确地说明等价或
  • Intellij IDEA:未命中断点,并显示为灰色

    在 Mac OS X 上运行 JDK 1 7 时 我的项目上的断点突然不起作用 并且显示为灰色 他们今天早些时候在工作 所以不确定我做了什么导致了这种情况 我正在使用 Intellij 13 1 3 为什么断点会像这样停止工作 天哪 我刚刚
  • php数组计数与动态结果

    我正在尝试计算从脚本返回的数组的结果 有两种情况我可以找回选项a是 Array Id gt 1779 SupplierId gt 1809 SupplierName gt cccccc 和第二个选项 ib Array 0 gt Array
  • 在delphi中禁用窗体大小调整

    有什么方法可以阻止用户调整表单大小吗 目前我正在使用 当表单大小改变时 MainForm Height 761 MainForm Width 777 但这看起来很可怕 因为当用户尝试更改表单大小时它会闪烁 固定尺寸很简单 你有两个选择 De
  • Cassandra Nodetool URISyntaxException:“索引 7 处的 IPv6 地址格式错误”

    Cassandra nodetool 更新 OpenJDK 后抛出错误 nodetool status nodetool Failed to connect to 127 0 0 1 7199 URISyntaxException Malf
  • 什么是托管代码和非托管代码? [复制]

    这个问题在这里已经有答案了 我发现有人说托管代码和非托管代码 有什么不同 它仅适用于 Net吗 你可以阅读这篇维基百科文章 托管代码 http en wikipedia org wiki Managed code 基本上托管代码是一个微软术
  • Box2D - b2body GetUserData 始终返回 null

    我正在尝试根据 box2d 中的 b2body 调整精灵的位置和旋转 创建主体后 我将 userData 属性设置为保存精灵和位置等的主体对象的属性 问题是在勾选方法 b gt GetUserData 中永远不会检索我放入其中的对象 你能看
  • GPS 对比加速度计计算距离

    我正在尝试实现一个健身应用程序 可以在Android 中跟踪跑步速度和跑步距离 看起来我可以使用 GPS 或加速度计来计算这些信息 由于跑步者可能会将手机放在手里 放在肩膀上或放在口袋里 所以我的第一直觉是使用 GPS 获取位置并计算跑步速
  • 如何将 SSH 密钥与 Jenkins 工作流插件结合使用

    有一个由以下执行的常规脚本Jenkins 工作流插件 https github com jenkinsci workflow plugin As 有记录的 https github com jenkinsci workflow plugin
  • 如何让 SWIG 在 C# 中处理 utf8 字符串?

    我正在编写一个可移植的 C 库 它与其他语言 java C python 绑定 我在以下人员的帮助下进行这些绑定SWIG http www swig org 我有一个用 C 编写的类 class MyClass public const c
  • 我可以对字段和构造函数参数使用相同的名称吗?

    class C T a public C T a a a 合法吗 是的 它是合法的并且适用于所有平台 它将正确地将您的成员变量 a 初始化为传入的值 a 一些更干净的人认为以不同的方式命名它们 但并非全部 我个人实际上经常使用它 具有相同变
  • 如何获取 NSString 的宽度?

    我正在尝试获取 NSString 的宽度 例如 NSString myString hello 有没有办法做到这一点 Thanks 这是一个相对简单的方法 只需创建一个具有适当字体的 NSAttributedString 并询问其大小 CG
  • Android 自定义组件中的布局未膨胀

    我在自定义视图中遇到空指针异常 源自LinearLayout 因为它找不到它的子视图 这是代码 public class MyView extends LinearLayout public MyView Context context A
  • DrawingContext.DrawLine:笔没有完全不透明度?

    当我画这样的东西时 这里只是随机画 public partial class MainWindow Window public MainWindow InitializeComponent DrawingVisual visual new
  • 专业密钥的许可证检查

    因此 我想制作一个加载了完整功能的免费应用程序 在应用程序检测到许可的专业版密钥之前 专业版功能将被禁用 当然 我想让专业密钥使用 LVL 检查其许可证 虽然到目前为止我知道如何正确做事 但我不知道如何使专业版密钥与应用程序进行通信以启用专
  • 当在封闭类模板中引用特化时,成员类模板的隐式实例化

    include