没有歧义的标识符

Che*_*Alf 8 c++

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.
}
Run Code Online (Sandbox Code Playgroud)

我认为这是一个编译器错误,因为我设计了代码来显示标识符由于与标准库的名称冲突而如何模糊不清.

这是编译器错误吗?


补充信息: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
Run Code Online (Sandbox Code Playgroud)

报告给微软(新的MS错误报告方案是非常错误的:它认为包装代码是一个好主意,然后拒绝让我上传源代码文件,除非我给它一个".txt"文件扩展名).

Oli*_*liv 5

这是编译器错误,因为编译器不应该为for_each调用执行模板参数推断.

唯一for_each可以匹配的声明定义为[alg.foreach]:

template<class InputIterator, class Function>
  Function for_each(InputIterator first, InputIterator last, Function f);
Run Code Online (Sandbox Code Playgroud)

应用于函数参数的模板参数推导f需要函数调用参数的类型log才能继续.但是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.
}
Run Code Online (Sandbox Code Playgroud)

它适用于此版本的MSVC,因为模板(曾经是/)是作为一种宏实现的,因此log作为名称传递,并且log在主体中调用的点执行重载决策for_each.


关于编辑:

表达式!!log相当于调用bool operator(bool)没有模板参数推导,编译器只是无法知道log它可以用来进行转换的哪个重载bool.

在表单的内部声明中auto x=y,x使用模板参数推导[dcl.type.auto.deduct]/4推导出实际类型:

如果占位符是自动类型说明符,则使用模板参数推导的规则确定推断类型T'替换T. [...]

所以MSVC的行为是错误的但是一致的.


M.M*_*M.M 2

定义您自己的::log会导致未定义的行为(无需诊断)。

从 C++17 (N4659) [extern.names]/3 开始:

使用外部链接声明的 C 标准库中的每个名称都保留给实现,用作具有 extern“C”链接的名称,无论是在命名空间 std 中还是在全局命名空间中。

相关答案的链接