【问题标题】:Unable to instantiate function templates which uses decltype to deduce return type, if called from inside a lambda?如果从 lambda 内部调用,则无法实例化使用 decltype 推断返回类型的函数模板?
【发布时间】:2011-01-21 02:06:51
【问题描述】:

我正在尝试使用 C++0x,特别是 lambda 表达式和 decltype 来简化我的一些代码,使用 MSVC10 RC 编译器。

我遇到了以下非常奇怪的问题:

template <typename F>
auto foo(F f) -> decltype(f()){
  return f();
}

template <typename F>
void bar(F f){
  f();
}

int main() {
  bar([](){
    foo([]() { }); // error C2893: Failed to specialize function template ''unknown-type' foo(F)'
  });
}

如注释中所示,编译器在foo([]() { }) 行生成错误。

我讨厌大喊“编译器错误”,但我真的看不出这个错误有什么好的解释。 显然,在外部 lambda 表达式内部时,编译器无法将 foo 函数模板专门用于内部 lambda。

但是,如果 foo 的定义更改为硬编码返回类型,如下所示:

template <typename F>
void foo(F f){
  return f();
}

然后一切编译就好了。

当用于在我不知道的另一个 lambda 范围内推断 lambda 表达式参数的返回类型时,是否存在一些模糊的 decltype 怪癖?

【问题讨论】:

  • 由于我无法访问该编译器:将尾随返回类型部分更改为 -&gt; decltype(void(), f()) 有帮助吗?
  • @Johannes:不,还是一样的结果
  • 如果您删除 bar 并尝试使用空 lambda 实例化 foo 会发生什么? foo( [](){} )
  • @David:然后它工作正常。这几乎是我能想出的最小的样本,它仍然重现了这个问题。
  • 如果它与:stackoverflow.com/questions/2122282/… 相关,我不会感到惊讶。似乎 lambda 和 scope 在 VS2010 中不能很好地配合使用。顺便说一句,我的错误仍然存​​在于 RC 中。

标签: c++ lambda c++11 visual-c++-2010 decltype


【解决方案1】:

'auto' 的本质是允许编译器计算类型。但是您的第一个示例包含相互之间的递归引用,因此要计算 foo 的 auto,您需要 bar 并创建 bar 的实例,您需要 foo。

另一方面,第二个例子明确地告诉编译器:“它应该是一个指向函数的指针,所以冷静一下”。由于指向函数的指针是经过良好计算的,因此类型编译器知道将保留什么。 仅作类比:比较成员的前向声明

struct A; //forward
...
A a1; //this is an error
A *a2; //this is correct since pointer calculated in bytes

【讨论】:

  • 嗯,据我所知,foo 并不依赖于barfoo 只是一个虚拟函数,它评估作为参数传递的函子,并返回结果。并以一个小的无操作 lambda 作为其参数来调用它。与bar 完全无关。我在这里遗漏了一些非常明显的东西吗?
  • @jalf - 指定模板函数并隐式使用它会强制编译器计算类型。只需尝试将隐式更改为显式: foo([]() { });
  • 但是 foo 的模板参数只是未命名的 lambda(我不能很好地明确指定)。它应该能够在完全不参考bar 的情况下推断出该类型
  • foo 使用隐含的模板参数 F,但为什么要从 bar 推导出来呢?我仍然没有看到它。请记住,它们是两个不同的 lambda 表达式。传递给 bar 的 lambda 与传递给 foo 的 lambda 无关。
  • @Dewfy,我也不明白你的意思。这与int a(int); template&lt;typename T&gt; T g(T); template&lt;typename T&gt; void f(T); int main() { f(a(g(a(0)))); } 有何不同?
【解决方案2】:

这些只是供人们观察的一些测试用例。

作品

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

void dummy() {}

int main()
{
    auto x = []()
            {   // non-lambda parameter
                foo(dummy);
            };
}

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto f = [](){};
    auto x = [&]()
            {    // pre-defined lambda
                foo(f);
            };
}

失败

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto x = []()
            {   // in-argument lambda
                foo([]{});
            };
}

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto x = []()
            {   // in-scope lambda
                auto f = []{};
                foo(f);
            };
}

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto x = []()
            {   // in-scope lambda, explicit return
                // (explicit return type fails too, `-> void`)
                auto f = [](){ return; };
                foo(f);
            };
}

template <typename F>
auto foo(F f) -> decltype(f())
{
  return f();
}

int main()
{
    auto x = []()
            {   // in-argument lambda, explicit return non-void
                // (explicit return type fails too, `-> int`)
                foo([]{ return 5; }); 
            };
}

所以它似乎确实与范围 和内部 lambda 的 void 类型有关,即使是显式的。(?)

【讨论】:

  • 有趣。看起来你遇到了一些非常相似的问题。绝对看起来像一个编译器错误
  • @jalf:是的,希望他们也能修复它。
  • 我添加了一个工作示例:问题似乎仅在foo 的参数返回类型为void 时出现
  • @David,我想知道如果我们将内部 lambda 更改为 []() -&gt; void { }[]() { return void(); } 是否有效?
  • 我用[]()-&gt;void {} 测试过,但它没有编译。我手头没有 VS2010,所以我无法测试 [](){ return void(); }(你真的可以在 return 语句中这样做吗?)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
  • 2013-12-05
  • 1970-01-01
相关资源
最近更新 更多