Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not ambiguous identifier

Tags:

c++

Visual C++ 2017 compiles the following cleanly, calling the user-defined 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.
}

I think that's a compiler bug, since I designed the code to show how an identifier can be ambiguous due to name collision with the standard library.

Is it a compiler bug?


Supplemental info: MinGW g++ 7.2 issues several error messages. They're not exactly informative, 15 lines complaining about std::for_each, but evidently they're due to the name collision. Changing the name of log the code compiles nicely.


Update: Further checking indicates that it's clearly a compiler bug, because Visual C++ compiles the following (except when symbol D is defined):

#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

Reported to Microsoft (the new MS bug reporting scheme is very buggy: it thought it was a good idea to word-wrap the code, then refused to let me upload source code file unless I gave it a ".txt" filename extension).

like image 355
Cheers and hth. - Alf Avatar asked Mar 21 '18 03:03

Cheers and hth. - Alf


Video Answer


2 Answers

This is a compiler bug because the compiler should not be able to perform template argument deduction for the for_each call.

The only declaration of for_each that could match is defined as [alg.foreach]:

template<class InputIterator, class Function>
  Function for_each(InputIterator first, InputIterator last, Function f);

Template argument deduction applied on function parameter f needs the type of the function call argument log to proceed. But log is overloaded, and an overload set of functions does not have a type.

For example, this simpler code should not compile for the same reason:

#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.
}

It works in this version of MSVC because templates (used to be/) are implemented as a kind of macro, so log is passed as a name, and overload resolution is performed at the point where log is called in the body of for_each.


About the edit:

The expression !!log is equivalent to a call to bool operator(bool) there are no template argument deduction, the compiler just can not know which overload of log it can use to make the conversion to bool.

Inside declaration of the form auto x=y, the actual type of x is deduced using template argument deduction [dcl.type.auto.deduct]/4:

If the placeholder is the auto type-specifier, the deduced type T' replacing T is determined using the rules for template argument deduction. [...]

So the behavior of MSVC is wrong but consistent.

like image 160
Oliv Avatar answered Sep 19 '22 10:09

Oliv


Defining your own ::log causes undefined behaviour (no diagnostic required).

From C++17 (N4659) [extern.names]/3:

Each name from the C standard library declared with external linkage is reserved to the implementation for use as a name with extern "C" linkage, both in namespace std and in the global namespace.

Link to related answer.

like image 38
M.M Avatar answered Sep 21 '22 10:09

M.M