2017-05-08 88 views
0

我正在尝试编写一个函数,该函数基本上将一个类型模板化的类的实例转换为第二个类型模板化的同一类的实例。我想避免在调用函数时显式声明模板类型。从lambda的模板参数演绎

这里是什么,我试图做一个最小的编译例子:

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; 
} 

在取消了编译错误的第一transform通话效果:

的Visual Studio 2017年:

error C2784: 'Container<B> transform(Container<A>,B (__cdecl *)(A))': could not deduce template argument for 'B (__cdecl *)(A)' from 'test::<lambda_afc081691b59f849887abca17e74b763>' 

无论克版本++ 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; }); 
               ^

这是否意味着编译器不可能推导出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{}))>{}; 
} 

但现在的函数签名是有点不太可读的错误信息,如果我提供一个不恰当的功能我得到的是相当不友好。使用std::function<B(A)>也没有帮助。

有没有一种方法来使用更紧密指定的函数参数与lambdas和没有明确添加模板类型?

回答

2

您需要捕捉少拉姆达转换成瓶坯操作的静态函数。该转换实际上可以通过运算符的一元运算符相当容易地调用。

transform(c, +[](int in) -> int { return in + 1; }); 

由于捕获更少的λ的闭合类型具有转换操作者ret(*)(params),编译器会遇到+时调用它。这是因为您实际上可以将+应用于指针类型。

[expr.unary.op/7]

一元+运算的操作数应具有算术,无作用域枚举,或指针类型,结果是论证的值。整型提升在整型或枚举操作数上执行。结果的类型是提升操作数的类型。

+0

我从来没有听说过的'+'的把戏了。俏皮。 Coliru的g ++会接受这一点,但VS2015和VS2017失败时会出现一个有趣的''operator +'模糊不清的错误,无法区分''和'',所以不幸的是我无法使用这个把戏。 – Rook

+0

@Rook - 当然MSVC会拒绝它......对不起,我不知道如何解决这个问题。 – StoryTeller

+0

既然参数是一个函数,不应该将lambda转换为函数指针隐式发生? – bolov

1

BA不能在B(func)(A)从拉姆达推断出来。

你可能会改变你的模板更通用的,是这样的:

template <template <typename...> class Container, typename Ts...> 
auto transform(const Container<Ts...>& c, F f) 
-> Container<std::decay_t<decltype(f(*c.begin())>> 
{ 
    return {}; 
} 
相关问题