I'm trying to write logging feature that will print object id if it is exist. VS 2019 compiles and works fine but Clang fails. How to get worked for Clang?
NOTE: "log" member can be present or absent - depends from class developer. It is optional. Global "log" variable will be present always.
Short example:
int i = 0;
struct S {
int i = 1;
int f() {
return i;
}
static int g() {
return [&](){
return i;
}();
}
};
full example
#include <cstdio>
#include <cassert>
#include <string>
using std::string;
#define LOG(x) [&]() \
{ \
log.print(x); \
} \
();
namespace myspace {
class Log
{
public:
Log(string id)
: m_Id(id)
{
}
void print(const string& str)
{
printf("%s %s\n",m_Id.c_str(),str.c_str());
}
private:
string m_Id;
};
Log log("global_id");
class MyClass
{
public:
MyClass()
: log("local_id")
{
}
void doSomething()
{
LOG("doSomething");
}
static void doSomethingStatic()
{
LOG("doSomethingStatic");
}
public:
Log log;
};
void test()
{
MyClass obj;
obj.doSomething();
MyClass::doSomethingStatic();
}
}// ns
int main()
{
myspace::test();
return 0;
}
Expected output (VS 2019, compilation success):
local_id doSomething
global_id doSomethingStatic
Actual output(clang version 8.0.1, compilation error)
main.cpp(46,5): error: invalid use of member 'log' in static member function
main.cpp(10,7): note: expanded from macro 'LOG'
You are doing unqualified name lookup. The standard says this (emphasis mine):
[basic.lookup.unqual]#1
In all the cases listed in [basic.lookup.unqual], the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name. If no declaration is found, the program is ill-formed.
The note [class.static.mfct]#1 clarifies that the rules of [class.mfct] also apply to static member functions. Those include another note that refers us to [basic.unqual.lookup].
Regarding this being in a lambda, we can find:
[expr.prim.lambda.closure]#12
The lambda-expression's compound-statement yields the function-body ([dcl.fct.def]) of the function call operator, but for purposes of name lookup [...], the compound-statement is considered in the context of the lambda-expression.
In other words, name lookup in the lambda function body happens as if we were in the surrounding scope (the static member function), so the above still applies.
You cannot circumvent this with explicit captures either (i.e. [&log](){...}();), because
[expr.prim.lambda.capture]
The identifier in a simple-capture is looked up using the usual rules for unqualified name lookup; [...]
In the end, it boils down to the above bold highlight: Unqualified name lookup stops as soon as a matching name is found (whether you wanted that name or not). Since the non-static log member is found before the global log variable, lookup stops there. I don't think you can work around this problem, it's just how unqualified lookup and (static) member functions are specified to work. Qualified name lookup is (for once) not the way out, for obvious reasons.
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