为什么失败这个模板参数推断?

时间:2012-05-21 17:24:15

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

我试图理解为什么这个代码段失败了:

#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<lambdaType>*,lambdaType应具有公共函数签名void( Handler<LambdaType>*)。我没有看到上面的例子有任何明显的错误(你知道,除了lambda和处理程序类型之间的丑陋和轻微的病态循环依赖)

2 个答案:

答案 0 :(得分:5)

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

Clang使用以下代码段很好地说明了另一个问题:

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

  

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

答案 1 :(得分: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([](...) { ... });

它会正常工作。