我有一个类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); }))
{
}
};
这允许我用显式function
对象构造类:
Value<int> i;
Foo foo0(i, function<bool()>([]() { return true; }));
Foo foo1(i, function<bool(const Value<int> &)>([](const auto &) { return true; }));
但是在尝试直接使用lambda时失败了:
Foo fooL1(i, [](const Value<int> &) { return true; });
由于某种原因我还不了解编译器没有考虑构造函数模板中从lambda到function
的隐式转换的可用性。错误消息是(Visual C ++ 2015,Update 3):
错误C2664:'Foo :: Foo(Foo&amp;&amp;)':无法转换参数2 “主::&LT; lambda_f1d2143f356d549800fb3412d8bc61a2&GT;”至 “的std ::功能&LT; bool(void)&gt;'
现在我可以为lambdas添加另一个构造函数模板
template<typename T, typename UnaryPredicate>
Foo(Value<T> &value, UnaryPredicate predicate) :
Foo(value, function<bool(const Value<T> &)>(predicate))
{
}
只要传递给该构造函数的lambda有一个参数Value<T>
,它就可以正常工作,但是对于没有参数的lambdas,它自然会失败:
Foo fooL0(i, []() { return true; });
所以我可能需要一些SFINAE魔法来为不同的lambdas启用适当的构造函数模板,例如:
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))
{
}
或者可能是完全不同的解决方案?问题是如何启用构造函数重载以使用适当的lambdas。
答案 0 :(得分:4)
你的问题是C ++平等对待所有论点,并尝试从所有论点中推断出你的模板论证。
未能推断出使用的模板参数是一个错误,而不仅仅是不一致的推论。它只是没有采取匹配的和#34;与它一起使用#34;。
我们可以将模板参数标记为非推导:
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
仅从第一个参数推断出来。第二次正常转换。
(次要格式更改/优化/代码缩短适用于Foo
以外的block_deduction
。