Passing different lambdas to function template in c++ -
i have class foo
accepts different predicate variants through 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 construct class 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; }));
however fails when trying use lambda directly:
foo fool1(i, [](const value<int> &) { return true; });
for reason don't understand yet compiler not consider availability of implicit conversion lambda function
in constructor template. error message (visual c++ 2015, update 3):
error c2664: 'foo::foo(foo &&)': cannot convert argument 2 'main::< lambda_f1d2143f356d549800fb3412d8bc61a2>' 'std::function< bool (void)>'
now can add constructor template lambdas
template<typename t, typename unarypredicate> foo(value<t> &value, unarypredicate predicate) : foo(value, function<bool(const value<t> &)>(predicate)) { }
which work fine long lambda passed constructor has 1 parameter of value<t>
, naturally fails lambdas without parameter:
foo fool0(i, []() { return true; });
so need sfinae magic enable appropriate constructor template different lambdas, 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 1 constructor template trick, like:
template<typename t, typename unarypredicate> foo(value<t> &value, unarypredicate predicate) : foo(value, function<???decltype(unarypredicate)???>(predicate)) { }
or maybe different solution? question how enable constructor overloads work appropriate lambdas.
your problem c++ treats arguments equally, , attempts deduce template arguements of them.
failure deduce template arguments used error, not inconsistent deduction. doesn't take ones match , "go it".
we can mark template argument 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>>;
then:
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); } ) {}
now t
deduced first argument. normal conversion occurs 2nd.
(minor formatting changes/optimizations/code shortening applies foo
beyond block_deduction
included.)
Comments
Post a Comment