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).
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With