在C ++中将不同的Lambda传递给函数模板 [英] Passing different lambdas to function template in c++

查看:65
本文介绍了在C ++中将不同的Lambda传递给函数模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Foo 类,该类通过其构造函数接受不同的谓词变体。

I have a class Foo that accepts different predicate variants through its constructor.

template<typename T>
struct Value
{
    T value;
};

class Foo
{
public:
    template<typename T>
    Foo(Value<T> &value, function<bool()> predicate)
    {
    }

    template<typename T>
    Foo(Value<T> &value, function<bool(const Value<T> &)> predicate) :
        Foo(value, function<bool()>([&value, predicate](){ return predicate(value); }))
    {
    }
};

这使我可以使用显式函数对象:

This allows me to construct the class with explicit function object:

Value<int> i;
Foo foo0(i, function<bool()>([]() { return true; }));
Foo foo1(i, function<bool(const Value<int> &)>([](const auto &) { return true; }));

但是在尝试直接使用lambda时会失败:

however it fails when trying to use a lambda directly:

Foo fooL1(i, [](const Value<int> &) { return true; });

出于某种原因,我仍然不知道编译器没有考虑从lambda到隐式转换的可用性构造函数模板中的函数。错误消息是(Visual C ++ 2015更新3):

For a reason I don't understand yet the compiler does not consider availability of implicit conversion from lambda to function in constructor template. The error message is (Visual C++ 2015, Update 3):


错误C2664:'Foo :: Foo(Foo&) ':无法从
'main ::<转换参数2。 lambda_f1d2143f356d549800fb3412d8bc61a2>至
’std :: function< bool(void)>'

error C2664: 'Foo::Foo(Foo &&)': cannot convert argument 2 from 'main::< lambda_f1d2143f356d549800fb3412d8bc61a2>' to 'std::function< bool (void)>'

现在我可以为lambda添加另一个构造器模板

Now I can add another constructor template for lambdas

template<typename T, typename UnaryPredicate>
Foo(Value<T> &value, UnaryPredicate predicate) :
    Foo(value, function<bool(const Value<T> &)>(predicate))
{
}

只要传递给该构造函数的lambda具有一个参数值< T> ,但是对于没有参数的lambda,它自然会失败:

which will work fine as long as the lambda passed to that constructor has one parameter of Value<T>, however it naturally fails for lambdas without parameter:

Foo fooL0(i, []() { return true; });

所以我可能需要一些SFINAE魔术来为不同的lambda启用适当的构造函数模板,例如: / p>

So I would probably need some SFINAE magic to enable appropriate constructor template for different lambdas, something like:

template<typename T, typename UnaryPredicate,
    typename = enable_if_t<is_callable_without_args> >
Foo(Value<T> &value, UnaryPredicate predicate) :
    Foo(value, function<bool()>(predicate))
{
}

template<typename T, typename UnaryPredicate,
    typename = enable_if_t<is_callable_with_one_arg> >
Foo(Value<T> &value, UnaryPredicate predicate) :
    Foo(value, function<bool(const Value<T> &)>(predicate))
{
}

或者也许只有一个构造函数模板可以完成任务,例如:

Or maybe only one constructor template could do the trick, something like:

template<typename T, typename UnaryPredicate>
Foo(Value<T> &value, UnaryPredicate predicate) :
    Foo(value, function<???decltype(UnaryPredicate)???>(predicate))
{
}

还是完全不同的解决方案?问题是如何使构造函数重载能够与适当的lambda一起使用。

Or maybe a completely different solution? The question is how to enable constructor overloads to work with appropriate lambdas.

推荐答案

您的问题是C ++平等地对待所有参数,并且

Your problem is that C++ treats all arguments equally, and attempts to deduce your template arguements from all of them.

未能推断出所使用的模板参数是一个错误,而不仅仅是不一致的推论。

Failure to deduce the template arguments used is an error, not just inconsistent deduction. It just doesn't take the ones that match and "go with it".

我们可以将模板参数标记为非推导:

We can mark a template argument as non-deduced:

template<class T> struct tag_t {using type=T;};
template<class Tag> using type=typename Tag::type;

template<class T>
using block_deduction = type<tag_t<T>>;

然后:

template<class T>
Foo(
  Value<T> &value,
  block_deduction<function<bool(const Value<T> &)>> predicate
) :
  Foo(
    value,
    [&value, predicate=std::move(predicate)]{ return predicate(value); }
  )
{}

现在 T 仅从第一个参数推导出。正常转换发生在第二个。

now T is deduced only from the first argument. Normal conversion occurs for 2nd.

(较小的格式更改/优化/代码缩短适用于 Foo 超出 block_deduction 也包括在内。)

(Minor formatting changes/optimizations/code shortening applies to your Foo beyond block_deduction also included.)

这篇关于在C ++中将不同的Lambda传递给函数模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆