为什么此模板参数推理失败

why fails this template parameter inference?

本文关键字:推理 失败 参数 为什么      更新时间:2023-10-16

我试图理解为什么这个片段失败:

#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 和处理程序类型之间的丑陋和略带病态的循环依赖关系(

一个问题是,正如@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

否则,变量的类型是从其初始值设定项推导的。要声明的变量的名称不应出现在初始值设定项表达式中。[...]

类型推导不适用于构造函数。 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([](...) { ... });

它会正常工作。