不是模棱两可的标识符
Not ambiguous identifier
>Visual C++ 2017 通过调用用户定义的log
干净地编译以下内容:
// Source encoding: UTF-8 with BOM ∩
#include <algorithm> // std::for_each
#include <iostream>
#include <math.h> // ::(sin, cos, atan, ..., log)
#include <string> // std::string
void log( std::string const& message )
{
std::clog << "-- log entry: " << message << std::endl;
}
auto main()
-> int
{
auto const messages = { "Blah blah...", "Duh!", "Oki doki" };
std::for_each( messages.begin(), messages.end(), log ); // C++03 style.
}
我认为这是一个编译器错误,因为我设计代码是为了显示标识符如何由于与标准库的名称冲突而变得不明确。
是编译器错误吗?
补充信息:MinGW g++ 7.2 发布了几条错误消息。它们的信息并不完全,有15行抱怨std::for_each
,但显然是由于名称冲突。更改代码log
的名称可以很好地编译。
更新:进一步检查表明这显然是一个编译器错误,因为 Visual C++ 编译以下内容(定义符号D
时除外):
#include <cmath> // std::(sin, cos, atan, ..., log)
#include <string> // std::string
namespace my{ void log( std::string const& ) {} }
using std::log;
using my::log;
auto main()
-> int
#ifdef D
{ return !!log; }
#else
{ auto f = log; return f==my::log; }
#endif
报告给Microsoft(新的 MS 错误报告方案非常错误:它认为对代码进行文字换行是个好主意,然后拒绝让我上传源代码文件,除非我给它一个".txt"文件扩展名)。
这是一个编译器错误,因为编译器应该无法对for_each
调用执行模板参数推断。
唯一可以匹配的for_each
声明定义为 [alg.foreach]:
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);
应用于函数参数的模板参数推导f
需要函数调用参数的类型log
才能继续。但是日志是重载的,并且重载的函数集没有类型。
例如,出于同样的原因,不应编译此更简单的代码:
#include <algorithm> // std::for_each
#include <string> // std::string
void log( std::string const& message );
void log();
auto main()
-> int
{
auto const messages = { "Blah blah...", "Duh!", "Oki doki" };
std::for_each( messages.begin(), messages.end(), log ); //template argument deduction for template parameter Function failed.
}
它适用于此版本的 MSVC,因为模板(以前是/)是作为一种宏实现的,因此log
作为名称传递,并且在for_each
正文中调用log
的位置执行重载解析。
关于编辑:
表达式!!log
相当于调用bool operator(bool)
没有模板参数推导,编译器只是不知道可以使用哪个重载log
进行bool
转换。
在形式auto x=y
的内部声明中,使用模板参数推导 [dcl.type.auto.deduct]/4 推导出x
的实际类型:
如果占位符是自动类型说明符,则使用模板参数推导规则确定推导的类型 T' 替换 T。[...]
因此,MSVC的行为是错误的,但始终如一。
定义自己的::log
会导致未定义的行为(无需诊断)。
从 C++17 (N4659) [extern.names]/3:
使用外部链接声明的 C 标准库中的每个名称都保留给实现,以便在命名空间 std 和全局命名空间中用作具有外部"C"链接的名称。
链接到相关答案。
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- #ifdef和未声明的标识符
- f2、f3、f4标识符未找到
- "Inverse SFINAE"避免模棱两可的过载
- 设置 Visual Studio for MPI: 找不到标识符错误
- 未声明的标识符编译暗黑破坏神 2 程序"muleview"
- 在顶点着色器中使用 OpenGl 的未声明标识符,我在顶点着色器中绘制三角形时遇到问题
- Google protobuf 时间戳未声明标识符,在 Windows 上具有C++
- 操作员C++的模棱两可的过载
- 如何让 GCC/Clang 在保留标识符上出错
- 模棱两可的重载模板
- 错误 C2760:语法错误:映射迭代器上意外的标记"标识符",预期的";"
- 当简单捕获中的标识符显示为参数的声明符 ID 时,没有编译器诊断
- 使用说明符 extern 声明的C++中的标识符链接
- C++:枚举:错误:应使用标识符而不是"}"
- 为什么我们不能重复使用具有不同模板参数的别名模板标识符?
- 调用重载的"<大括号括起来的初始值设定项列表>"对于对来说就足够了是模棱两可的
- Visual Studio C++ PlaySound 标识符未定义
- 不是模棱两可的标识符
- 用模棱两可的标识符铸造无效的指针