C++17的类模板参数推导功能能否推导局部类型?

8

P0091R3 ("类模板模板实参推导") 最近被添加到 gcc trunk 中,可以在 wandbox 上进行测试。

我心中想到的是使用它来用非常少的代码实现"作用域保护"

scope_guard _([]{ cout << "hi!\n" });

我尝试在wandbox上实现它...

template <typename TF>
struct scope_guard : TF
{
    scope_guard(TF f) : TF{f} { }
    ~scope_guard() { (*this)(); }
};

int main() 
{
    scope_guard _{[]{}};
}

...但编译失败,出现了以下错误:

prog.cc:6:5: error: 'scope_guard(TF)-> scope_guard<TF> [with TF = main()::<lambda()>]', declared using local type 'main()::<lambda()>', is used but never defined [-fpermissive]
     scope_guard(TF f) : TF{std::move(f)} { }
     ^~~~~~~~~~~

然后我尝试了使用非lambda本地类型,但是得到了相同的错误。

int main() 
{
    struct K { void operator()() {} };
    scope_guard _{K{}};
}

之后,我尝试了一个非本地类型,它按预期工作。
struct K { void operator()() {} };

int main() 
{
    scope_guard _{K{}};
}

这个功能的设计是否防止本地类型被推断?

或者这是gcc当前实现中的一个缺陷吗?


1
看起来你已经找到并评论了这个错误报告。 - Barry
1个回答

7

这是当前实现中的一个错误:77890NEW意味着有效性,而不是未确认已在7.0中修复)。能够推断lambda是原始论文的激励示例之一,因此如果它不能工作,则会非常尴尬:

// Virtually impossible to pass a lambda to a template class' constructor without declaring the lambda
for_each(vi2.begin(), vi2.end(), Foo<???>([&](int i) { ...}));
for_each(vi.begin(), vi.end(), Foo([&](int i) { ...})); // Now easy instead of virtually impossible
我们可以创建一个非常基础的示例:
template <typename TF>
struct scope_guard
{
    scope_guard(TF ) { }
};

int main()
{
    scope_guard _([]{});
}

这应该对由以下函数组成的合成函数集进行重载分辨率:
template <class TF> scope_guard<TF> synthesized(TF );
template <class TF> scope_guard<TF> synthesized(scope_guard<TF> const& );
template <class TF> scope_guard<TF> synthesized(scope_guard<TF>&& );

应该选择第一个重载并将其返回类型用作_的类型,其中TF是lambda的类型。这应该可以正常工作。


原来的代码现在可以在wandbox上成功编译了。 - Vittorio Romeo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接