C++ 将不同的lambda传递给c++;

C++ 将不同的lambda传递给c++;,c++,lambda,c++14,template-meta-programming,sfinae,C++,Lambda,C++14,Template Meta Programming,Sfinae,我有一个类Foo,它通过构造函数接受不同的谓词变量 template<typename T> struct Value { T value; }; class Foo { public: template<typename T> Foo(Value<T> &value, function<bool()> predicate) { } template<typename T>

我有一个类
Foo
,它通过构造函数接受不同的谓词变量

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); }))
    {
    }
};
但是,在尝试直接使用lambda时失败:

Foo fooL1(i, [](const Value<int> &) { return true; });
只要传递给该构造函数的lambda有一个参数
Value
,它就可以正常工作,但是对于没有参数的lambda,它自然会失败:

Foo fooL0(i, []() { return true; });
因此,我可能需要一些SFINAE魔法来为不同的lambda启用适当的构造函数模板,例如:

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))
{
}
template<typename T, typename UnaryPredicate>
Foo(Value<T> &value, UnaryPredicate predicate) :
    Foo(value, function<???decltype(UnaryPredicate)???>(predicate))
{
}
模板
Foo(值和值,一元谓词):
Foo(值、函数(谓词))
{
}
模板
Foo(值和值,一元谓词):
Foo(值、函数(谓词))
{
}
或者,可能只有一个构造函数模板可以完成此任务,例如:

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))
{
}
template<typename T, typename UnaryPredicate>
Foo(Value<T> &value, UnaryPredicate predicate) :
    Foo(value, function<???decltype(UnaryPredicate)???>(predicate))
{
}
模板
Foo(值和值,一元谓词):
Foo(值、函数(谓词))
{
}

或者是一个完全不同的解决方案?问题是如何让构造函数重载与适当的lambdas一起工作。

< p>您的问题是C++平等地对待所有的参数,并试图从所有的推导中推导出模板的争论。

未能推断所使用的模板参数是一个错误,而不仅仅是不一致的推断。它只是不需要那些匹配的和“随它去”

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

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>>;
模板结构标记{using type=t;};
模板使用type=typename标签::type;
模板
使用block_演绎=类型;
然后:

模板
福(
价值与价值,
块推理谓词
) :
福(
价值
[&value,predicate=std::move(predicate)]{返回谓词(value);}
)
{}
现在,
T
仅从第一个参数推导得出。正常转换发生在第二个


(小的格式更改/优化/代码缩短适用于您的
Foo
beyond
block\u演绎也包括在内。)

太好了,虽然我看不出背后的魔力,但它就像一个魅力。你最终能给我指出一些用人类可读的形式描述这种技术的信息吗?谢谢。@manisin block deducton接受一个类型,并返回一个相同类型的。但是返回的类型不再是可推断的。模板类型推断是模式匹配,
tag_t::type
不能与模式匹配。简言之,因为标准如此规定。为什么会这样说?理论上::type
可能与
T
无关,实际上它是
T
。C++不需要类型推断系统来反转任意图灵完整的过程,并且<代码> TAGYT::类型< /C>可以任意映射从<代码> 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); }
  )
{}