无法推断模板参数(向量,std::function)

4

我创建了一个模板函数,试图自动推断模板参数。 MCVE(编译它):

template<class Value, class Allocator>
void foo(const std::vector<Value, Allocator>& v, const std::function<void(const Value&)>& f)
{
}

int main()
{
    vector<int> v;
    foo<int>(v, [](const int&){}); //okay
    //foo(v, [](const int&){}); //not okay
    return 0;
}

一开始我以为无法推导出分配器,但似乎这并没有解决问题。我猜测接下来的问题可能与将lambda转换为std :: function有关,但我对进一步步骤毫无头绪。有人知道我需要做什么才能使其可推导吗?

附注:我知道“const int&”可以变成“int”,但在实际代码中那里是非标量数据类型。


2
你可以摆脱 std::function 并使用以下代码:template void foo(const std::vector& v, Func&& f) { } - Jarod42
请注意,std::vector 可能有超过 2 个模板参数,而您的代码没有考虑到这一点。 - rubenvb
@rubenvb,您的意思是什么?在 https://en.cppreference.com/w/cpp/container/vector 上看到的实现只有 2 个模板参数。 - turoni
C++20 可能应该为此引入概念 :-) - Jarod42
@turoni 这就是规范。如果实现想要使用一些优化技巧或扩展功能,它可能会添加额外的模板参数,但仍然符合标准。 - rubenvb
显示剩余2条评论
1个回答

3

模板参数推导 在将 Lambda 隐式转换为 std::function 之前发生。

类型推导不考虑隐式转换(除了上面列出的类型调整):这是 重载决议 的工作,稍后会发生。

这意味着第二个函数参数 f 上的模板参数 Value 类型推导失败,因为不考虑从 Lambda 到 std::function 的隐式转换。

正如您所示,您可以明确指定模板参数(以绕过模板参数推导)。或者您可以使用 std::type_identity 将第二个参数声明为 非推断上下文,从而排除它的推导。

使用限定符标识符指定的类型的嵌套名称限定符(作用域解析运算符::左侧的所有内容):

例如:

template<class Value, class Allocator>
void foo(const std::vector<Value, Allocator>& v, const std::function<void(const std::type_identity_t<Value>&)>& f)
{
}

直播

PS: std::type_identity 从 C++20 开始支持;如果你使用的编译器不支持它,那么很容易自己实现一个。


1
可能需要一些时间才能理解为什么这个代码有效,但希望 https://en.cppreference.com/w/cpp/language/template_argument_deduction#Non-deduced_contexts 能够有所帮助。谢谢。 - turoni
我理解得对吗,std::type_identity<Value>::Type 是将左边范围解析运算符 :: 之前的第二个 Value 参数变成非推导上下文的原因? - turoni
1
@turoni 是的。然后Value只会在第一个函数参数中被推导出来,一切都没问题。 - songyuanyao
这让我陷入了比我预期更深的模板推导上下文的疯狂洞穴,但感谢您帮助我理解。 - turoni
1
std::type_identity 在其简洁性方面非常出色。我一定写了很多复杂的解决方案,而这些方案本可以使用像这样的辅助工具来简化。自己要记住:现在,_一定要_记住这个。 - Ted Lyngmo
1
@turoni,你在type_identity中将type定义为private,请将其改为public。 :) https://godbolt.org/z/7_DXBt - songyuanyao

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