C++ 中函数查找与模板的混淆

2023-11-30

从以下内容开始(使用gcc version 4.0.1):

namespace name {
   template <typename T>
   void foo(const T& t) {
      bar(t);
   }

   template <typename T>
   void bar(const T& t) {
      baz(t);
   }

   void baz(int) {
      std::cout << "baz(int)\n";
   }
}

如果我添加(在global命名空间)

struct test {};
void bar(const test&) {
   std::cout << "bar(const test&)\n";
}

然后,正如我所料,

name::foo(test()); // produces "bar(const test&)"

但如果我只是添加

void bar(const double&) {
   std::cout << "bar(const double&)\n";
}

它似乎找不到这个重载:

name::foo(5.0) // produces "baz(int)"

更重要的是,

typedef std::vector<int> Vec;
void bar(const Vec&) {
   std::cout << "bar(const Vec&)\n";
}

也没有出现,所以

name::foo(Vec());

给出编译器错误

error: cannot convert ‘const std::vector<int, std::allocator<int> >’ to ‘int’ for argument ‘1’ to ‘void name::baz(int)’

这是查找应该如何工作的吗? (注意:如果我删除命名空间name,然后一切都按我的预期进行。)

我如何修改这个示例,以便任何重载bar被认为? (我认为应该考虑重载before模板?)


我假设你添加了double版本也到全局名称空间,并且您调用foo定义完所有内容后从 main 开始。所以这基本上是两个阶段的名称查找。查找因调用中的参数依赖(取决于其类型)而依赖的非限定函数名是分两个阶段完成的。

第一阶段在定义上下文中进行不合格且依赖于参数的查找。然后它冻结结果,并使用实例化上下文(实例化点的声明之和)进行第二个参数相关查找only. No不再进行不合格的查找。所以对于你的例子来说这意味着:

  • 电话bar(t) within foo<test>仰望;查询bar在实例化上下文中使用依赖于参数的查找(它没有使用非限定查找找到它,因为foo被宣布above栏模板)。取决于你是否定义了全局bar之前或之后foo模板,它会找到全局bar声明使用参数依赖查找已经在第一阶段(它是在test的命名空间)。然后 main 中的调用将实例化foo<test>并且有可能发现bar在此阶段(如果您在声明模板之后声明它)。

  • 电话bar(t) within foo<int>不进行参数相关的查找(或者更确切地说,查找的结果是一个空的声明集),因为int是一个基本类型。因此,对定义上下文的不合格查找也将找不到任何内容,因为匹配bar模板已声明after the foo模板。该调用的格式不正确,该标准在以下位置描述了这种情况14.6.4.2/1

    如果调用格式不正确[...],则程序具有未定义的行为。

    因此,我认为您应该将其视为“我做了一件肮脏的事情,而编译器选择不打我”的情况:)

  • 电话bar(t) within foo<Vec>将再次进行查找,并在中查找 barstd::(因为那就是那里std::vector被定义为)。它没有找到一个bar在那里,不在定义上下文中。因此它决定再次采用未定义的行为,并使用bar模板,它本身又通过使用来执行未定义的行为baz在它之后声明,并且 ADL 和定义上下文中的非限定查找都无法找到它。

    如果向量是vector<test>,然后查找bar也将在全局范围内完成,因为依赖于参数的查找不仅会直接使用参数类型,还会直接使用其中的模板参数的类型(如果有)。


如果您使用 GCC,那么不要完全依赖它的行为。在下面的代码中,它声称调用是不明确的,尽管代码完全没问题 -f in afake不应成为候选人。

namespace aname {
  struct A { };
  void f(A) { }
}

namespace afake {
  template<typename T>
  void g(T t) { f(t); }
  void f(aname::A) { }
}

int main() { aname::A a; afake::g(a); }

如果您想测试您的代码片段是否符合一致性,最好使用comeau在线编译器与严格的设置。

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

C++ 中函数查找与模板的混淆 的相关文章

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

    所以我试图创建一个简单的程序 只需在单击图片框中更改图片即可 我目前只使用两张图片 所以我的图片框单击事件函数的代码 看起来像这样 private void pictureBox1 Click object sender EventArgs
  • 无法使用已与其底层 RCW 分离的 COM 对象。在 oledb 中

    我收到此错误 但我不知道我做错了什么 下面的代码在backrgroundworker中 将异常详细信息复制到剪贴板 System Runtime InteropServices InvalidComObjectException 未处理 通
  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • UML类图:抽象方法和属性是这样写的吗?

    当我第一次为一个小型 C 项目创建 uml 类图时 我在属性方面遇到了一些麻烦 最后我只是将属性添加为变量 lt
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • C - 找到极限之间的所有友好数字

    首先是定义 一对友好的数字由两个不同的整数组成 其中 第一个整数的除数之和等于第二个整数 并且 第二个整数的除数之和等于第一个整数 完美数是等于其自身约数之和的数 我想做的是制作一个程序 询问用户一个下限和一个上限 然后向他 她提供这两个限
  • C#:如何防止主窗体过早显示

    在我的 main 方法中 我像往常一样启动主窗体 Application EnableVisualStyles Application SetCompatibleTextRenderingDefault false Application
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • 如何将图像路径保存到Live Tile的WP8本地文件夹

    我正在更新我的 Windows Phone 应用程序以使用新的 WP8 文件存储 API 本地文件夹 而不是 WP7 API 隔离存储文件 旧的工作方法 这是我如何成功地将图像保存到 共享 ShellContent文件夹使用隔离存储文件方法
  • Github Action 在运行可执行文件时卡住

    我正在尝试设置运行google tests on a C repository using Github Actions正在运行的Windows Latest 构建过程完成 但是当运行测试时 它被卡住并且不执行从生成的可执行文件Visual
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • mysql-connector-c++ - “get_driver_instance”不是“sql::mysql”的成员

    我是 C 的初学者 我认为学习的唯一方法就是接触一些代码 我正在尝试构建一个连接到 mysql 数据库的程序 我在 Linux 上使用 g 没有想法 我运行 make 这是我的错误 hello cpp 38 error get driver
  • C 中的异或运算符

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

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

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我
  • 恢复上传文件控制

    我确实阅读了以下帖子 C 暂停 恢复上传 https stackoverflow com questions 1048330 pause resume upload in c 使用 HTTP 恢复上传 https stackoverflow

随机推荐