C++ 从lambda推导模板参数
我试图编写一个函数,基本上将一个在一种类型上模板化的类的实例转换为另一种类型上模板化的相同类的实例。我希望在调用函数时避免显式声明模板类型 下面是我尝试做的一个最小的可编译示例:C++ 从lambda推导模板参数,c++,templates,lambda,C++,Templates,Lambda,我试图编写一个函数,基本上将一个在一种类型上模板化的类的实例转换为另一种类型上模板化的相同类的实例。我希望在调用函数时避免显式声明模板类型 下面是我尝试做的一个最小的可编译示例: template<class T> class container {}; template <class A, class B, template <class C> class Container> Container<B> transform(Container&
template<class T> class container {};
template <class A, class B, template <class C> class Container>
Container<B> transform(Container<A> c, B(func)(A))
{
return Container<B>{};
}
int do_something(int in)
{
return in + 1;
}
int main()
{
container<int> c{};
//this one doesn't work:
//transform(c, [](int in) -> int { return in + 1; });
//these are fine:
transform<int, int>(c, [](int in) -> int { return in + 1; });
transform(c, do_something);
return 0;
}
默认情况下,g++coliru.stacked-crooked.com使用哪个版本:
main.cpp:4:14: note: template argument deduction/substitution failed:
main.cpp:18:52: note: mismatched types 'B (*)(A)' and 'main()::<lambda(int)>'
transform(c, [](int in) -> int { return in + 1; });
^
main.cpp:4:14:注意:模板参数推断/替换失败:
main.cpp:18:52:注意:类型“B(*)(A)”和“main():”不匹配
转换(c,[](intin)->int{returnin+1;});
^
这是否意味着编译器不可能推断lambda的签名,即使它已被明确定义为这样
我知道我可以像这样重写变换函数:
template <class A, template <class C> class Container, class F>
auto transform(Container<A> c, F func)->Container<decltype(func(A{}))>
{
return Container<decltype(func(A{}))>{};
}
模板
自动转换(容器c,F func)->容器
{
返回容器{};
}
但是现在函数签名的可读性差了一点,如果我提供了一个不合适的函数,我得到的错误消息是非常不友好的。使用std::function
也没有帮助
有没有一种方法可以在lambda中使用更严格指定的函数参数,而无需显式添加模板类型?您需要将无捕获lambda转换为执行操作的静态函数。使用一元
+
运算符的应用程序实际上可以相当容易地调用这种转换
transform(c, +[](int in) -> int { return in + 1; });
由于无捕获lambda的闭包类型有一个到ret(*)(params)
的转换运算符,编译器将在遇到+
时调用它。这是因为您实际上可以将+
应用于指针类型
一元+运算符的操作数应具有算术、非范围枚举、或指针类型,结果为参数值。对整数或枚举操作数执行整数提升。结果的类型是提升的操作数的类型
B
和A
不能在B(func)(A)
中从lambda推导出来
您可以将模板更改为更通用的模板,例如:
template <template <typename...> class Container, typename Ts...>
auto transform(const Container<Ts...>& c, F f)
-> Container<std::decay_t<decltype(f(*c.begin())>>
{
return {};
}
模板
自动转换(常量容器和c、F)
->容器
{
返回{};
}
我以前从未听说过+
这个把戏。漂亮。Coliru的g++可以接受这一点,但是VS2015和VS2017失败了,出现了一个有趣的“operator+”是不明确的错误,无法区分
和
,所以不幸的是我不能使用这个技巧。@Rook-当然MSVC会拒绝它。。。很抱歉,我不知道如何避开这个问题。因为参数是函数,所以lambda到函数指针的转换不应该隐式发生?@bolov-不是在推导的上下文中。它在标准中的某个地方,但我现在很难找到它。我在这里找到了另一个相同解决方案的参考:似乎MSVC多年来一直无法做到这一点。这有点令人失望。
template <template <typename...> class Container, typename Ts...>
auto transform(const Container<Ts...>& c, F f)
-> Container<std::decay_t<decltype(f(*c.begin())>>
{
return {};
}