Reputation: 145429
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).
Upvotes: 8
Views: 338
Reputation: 18081
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.
Upvotes: 5
Reputation: 141648
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.
Upvotes: 2