【问题标题】:why fails this template parameter inference?为什么这个模板参数推断失败?
【发布时间】:2012-05-21 17:24:14
【问题描述】:

我试图理解为什么这个 sn-p 失败:

#include <iostream>

using namespace std;


template <typename Lambda>
struct Handler
{
  bool _isCompleted;

  bool isCompleted() { return _isCompleted; }

  Lambda _l;
  Handler(Lambda&& l) : _l(l) {}

  void call() { _l(this); }
};

int main()
{
  auto l1 = new Handler( [&](decltype(l1) obj )->
{
  obj->_isCompleted = true;
  cout << " is completed?" << obj->isCompleted() << endl;
});
  l1->call();
};

g++ 4.5 失败:

test.cpp: In function ‘int main()’:
test.cpp:21:17: error: expected type-specifier before ‘Handler’
test.cpp:21:17: error: expected ‘,’ or ‘;’ before ‘Handler’
test.cpp:25:2: error: expected primary-expression before ‘)’ token
test.cpp:25:2: error: expected ‘;’ before ‘)’ token
test.cpp:26:7: error: request for member ‘call’ in ‘* l1’, which is of non-class type ‘int’

我的理解是 auto l1 应该解析为 Handler&lt;lambdaType&gt;* 并且 lambdaType 应该有一个公共函数签名 void( Handler&lt;LambdaType&gt;*)。我看不出上面的例子有什么明显的错误(你知道,除了 lambda 和处理程序类型之间的丑陋和稍微病态的循环依赖之外)

【问题讨论】:

  • 你不是要求你的编译器凭空合成一个类型,除了病态的周期性自依赖之外没有任何具体信息吗?

标签: c++ templates lambda c++11 type-inference


【解决方案1】:

一个问题是,正如@Cat 所说,模板参数推导不适用于构造函数调用。您总是需要指定模板参数。

Clang 用以下 sn-p 很好地说明了另一个问题:

struct X{
  X(...){}
};

int main(){
  auto l = X([](decltype(l)& o){});
}

输出:

t.cpp:6:26: error: variable 'l' declared with 'auto' type cannot appear in its
      own initializer
  auto l = X([](decltype(l)& o){});
                         ^
1 error generated.

强制性标准报价:

§7.1.6.4 [dcl.spec.auto] p3

否则,变量的类型是从它的初始化器推导出来的。被声明的变量的名称不应出现在初始化表达式中。 [...]

【讨论】:

  • 是的,g++ 诊断在 clang 面前显得苍白无力。我应该知道这一点。谢谢!
【解决方案2】:

类型推导不适用于构造函数。 auto 会推断出表达式的类型,是的,但是 new Handler() 需要显式类型。改为写一个工厂函数:

// also don't use raw owning pointers
template <typename L>
std::unique_ptr<Handler<L>> make_handler(L lambda) {
    return std::unique_ptr<Handler<L>>(new Handler<L>(lambda));
}

当然,这有点重复你自己,但只有一次。然后就可以了

auto l1 = make_handler([](...) { ... });
auto l2 = make_handler([](...) { ... });

它会正常工作的。

【讨论】:

  • 不过,这不是唯一的问题。另一个是auto声明的变量不能在自己的初始化器中使用。
  • 我同意,问题似乎是在 l1 初始化中使用 l1。即使解决了这些问题,我也会遇到更多错误
  • 模板参数推导确实适用于构造函数,但仅用于推导构造函数参数,而不是正在构造的类型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 2017-01-27
  • 1970-01-01
  • 2021-08-14
  • 2012-09-15
  • 1970-01-01
  • 2017-02-08
相关资源
最近更新 更多