【问题标题】:Are function-local typedefs visible inside C++0x lambdas?在 C++0x lambda 中是否可以看到函数局部类型定义?
【发布时间】:2011-01-08 12:00:46
【问题描述】:

我遇到了一个奇怪的问题。以下简化代码重现了 MSVC 2010 中的问题:

template <typename T>
struct dummy
{
    static T foo(void) { return T(); }
};

int main(void)
{
    typedef dummy<bool> dummy_type;
    auto x = []{ bool b = dummy_type::foo(); };
    // auto x = []{ bool b = dummy<bool>::foo(); }; // works
}

我在函数中本地创建的typedef 在 lambda 中似乎不可见。如果我将 typedef 替换为实际类型,它会按预期工作。

这里有一些其他的测试用例:

// crashes the compiler, credit to Tarydon
int main(void)
{
    struct dummy {};

    auto x = []{ dummy d; };
}

// works as expected
int main(void)
{
    typedef int integer;

    auto x = []{ integer i = 0; };
}

我现在没有可用的 g++ 来测试它。这是 C++0x 中的一些奇怪规则,还是只是编译器中的错误?

从上面的结果来看,我倾向于 bug。虽然崩溃绝对是一个错误。


目前,我已经提交了两个bug reports

上面的所有代码 sn-ps 都应该编译。该错误与在本地定义的范围上使用范围解析有关。 (被dvide发现。)

而崩溃错误与...谁知道呢。 :)


更新

根据bug reports,它们都已在 Visual Studio 2010 的下一个版本中得到修复。(虽然这似乎不是这种情况;也许是 VS11。)

【问题讨论】:

  • 与本地命名空间别名相同
  • 所有三个测试用例都使用英特尔 C++ 编译器 11.1 成功编译。
  • 三个测试用例都使用g++ 4.5编译成功。

标签: c++ lambda c++11 compiler-bug


【解决方案1】:

从 n3000,5.1.2/6,

lambda 表达式的 复合语句产生 函数的函数体(8.4) 呼叫操作员,但出于以下目的 名称查找(3.4),... 复合语句被认为是 lambda 表达式的上下文。

毫不奇怪,本地类型应该是可见的。

【讨论】:

  • 啊,我才意识到我无意中看到了一份较旧的草稿。
  • 我接受这个回答我原来的“这是否允许”问题。 :)
【解决方案2】:

lambda 也无法检测到函数局部枚举。

int main()
{   
    enum E {A, B, C};   
    auto x = [](){ int a = A; }; 
    //auto y = [](){ E a = A; }; // this will crash the compiler
}

错误 C3493:无法隐式捕获“A”,因为未指定默认捕获模式

以下是一种解决方法,但可能有问题。

int main()
{   
    enum E {A, B, C};   
    auto x = [=](){ int a = A; };
    // typedef E F; 
    // auto y = [=](){ F a = A; }; // this compiles ok
}

【讨论】:

    【解决方案3】:

    这并不是您问题的真正答案,而只是进一步探索问题。我想知道编译器是否在处理在封闭范围内声明的 types 时遇到问题,所以试了一下:

    #include <iostream>
    
    template <typename Func>
    void do_test(Func pFunc) {
    }
    
    template <typename T>
    void test_trait(void) {
       class Something { public: int foo; };
    
       do_test ([] (T pX) {
          Something A; A.foo = 12;
       });
    }
    
    int main(void) {
        test_trait<int> ();
    }
    

    在这里,我只是想在封闭范围内创建一个本地类型,并在 lambda 函数中使用它。这不仅不能编译(使用 Visual Studio 2010,Beta 2),而且实际上会使编译器因 C1001 内部错误而崩溃。

    【讨论】:

    • 奇怪的是,如果您将本地 typedef 设置为本地类型,崩溃就会消失。
    【解决方案4】:

    我已经提交了两个错误报告。

    我们会看看情况如何。 :)


    更新

    两个错误都已被标记为已修复:

    感谢您的反馈。我们之前已经发现了这个错误,我们已经在下一个版本中修复了它。感谢您使用该产品。

    谢谢,
    Ulzii Luvsanbat
    Windows C++ 团队

    所以我们开始了。

    【讨论】:

    • 它似乎与模板无关,而是与需要范围解析运算符 (::) 时有关。非静态 foo 方法按预期工作。
    • 你的命名空间问题是什么?它使用:: 来获取原始命名空间(工作版本)。也许每当本地定义需要:: 时?
    • @dvide:没关系。 :) 使用反引号:`code在这里`变成code goes here。 (注意,您可以使用反斜杠转义。)我正在修改第二份报告以匹配我们的数据。
    • @dvide:我已将“typedef-of-template”错误修改为更通用的“Lambda 范围解析失败,本地定义的范围。”。很好的发现。
    • @James @dvide:根据错误报告,这两个问题都已修复。
    猜你喜欢
    • 2013-09-13
    • 2020-08-24
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 2010-09-25
    相关资源
    最近更新 更多