我正在尝试编写日志记录功能,该功能将打印对象ID(如果存在)。VS 2019可以编译并正常运行,但Clang失败。如何为Clang工作?
注意:“ log”成员可以存在或不存在-取决于类开发人员。它是可选的。全局“ log”变量将始终存在。
简短示例:
int i = 0;
struct S {
int i = 1;
int f() {
return i;
}
static int g() {
return [&](){
return i;
}();
}
};
Run Code Online (Sandbox Code Playgroud)
完整的例子
#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;
}
Run Code Online (Sandbox Code Playgroud)
预期输出(VS 2019,编译成功):
local_id doSomething
global_id doSomethingStatic
Run Code Online (Sandbox Code Playgroud)
实际输出(Clang版本8.0.1,编译错误)
main.cpp(46,5): error: invalid use of member 'log' in static member function
main.cpp(10,7): note: expanded from macro 'LOG'
Run Code Online (Sandbox Code Playgroud)
您正在执行不合格的名称查找。标准说(强调我的):
[basic.lookup.unqual]#1
在[basic.lookup.unqual]中列出的所有情况下,都在作用域中搜索各个类别中列出的顺序的声明。找到名称声明后,名称查找就会结束。 如果找不到声明,则程序格式错误。
该说明[class.static.mfct]#1阐明的规则[class.mfct]也适用于静态成员函数。这些包括另一个注释,该注释将我们引向[basic.unqual.lookup]。
关于这种情况,我们可以找到:
[expr.prim.lambda.closure]#12
的λ-表达的化合物语句产率功能体([dcl.fct.def])的函数调用操作的,但对于名称查找的目的[... ],则在lambda-expression的上下文中考虑复合语句。
换句话说,在lambda函数主体中进行名称查找就像发生在周围的作用域中一样(静态成员函数),因此上述操作仍然适用。
您也不能通过显式捕获来规避这一点[&log](){...}();,因为
[expr.prim.lambda.capture]
的识别符在一个简单的捕获被查找使用不合格的名称查找通常的规则; [...]
最后,它归结为上面的粗体突出显示:一旦找到匹配的名称(无论您是否想要该名称),就会停止不合格的名称查找。由于非静态log成员位于全局log变量之前,因此查找在此处停止。我认为您无法解决此问题,这只是指定不合格的查找和(静态)成员函数起作用的方式。出于明显的原因,合格的名称查找(不是一次)不是出路。