How to resolve ambiguity inside a lambda that inside a static method?

Sma*_*mak 3 c++ lambda static

我正在尝试编写日志记录功能,该功能将打印对象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)

Max*_*hof 5

您正在执行不合格的名称查找。标准说(强调我的):

[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变量之前,因此查找在此处停止。我认为您无法解决此问题,这只是指定不合格的查找和(静态)成员函数起作用的方式。出于明显的原因,合格的名称查找(不是一次)不是出路。