c++ - Calling const mutable lambdas -


to simplify testcase, suppose have following wrapper class:

template <typename t> struct wrapper {   decltype(auto) operator()() const {     return m_t();   }   decltype(auto) operator()() {     return m_t();   }   t m_t; };  template <typename t> auto make_wrapper(t t) {   return wrapper<t>{t}; } 

and let’s wrapping following trivial functor returning references:

struct foo {   int& operator()() {     return x;   }   const int& operator()() const {     return x;   }   int x; }; 

in main function, trying wrap foo functor lambda closure. since want return non-const references, setting mutable , using decltype(auto):

int main() {   foo foo;   auto fun = [foo]() mutable -> decltype(auto) { return foo(); };   auto wfun = make_wrapper(fun);   const auto& cwfun = wfun;    wfun();     // <- ok   cwfun();    // <- bad! } 

for second call, cwfun(), first const version of wrapper::operator() called, there m_t viewed const lambda, , cannot called. suppose because m_t marked mutable in first place. way of making work? convert m_t non-const before calling in operator() const?

goals

my goal call cwfun() call wrapper::operator() const , foo::operator() const. mark wrapper::m_t mutable fix compiler error, foo::operator() called instead of foo::operator() const.

alternatively, can add const in wrapper::operator() const since know foo::operator() , foo::operator() const differ constness. using like:

return const_cast<typename std::add_lvalue_reference<typename std::add_const<typename std::remove_reference<decltype(m_t())>::type>::type>::type>(m_t()); 

but yes, that’s heavy.

errors , coliru paste

the error message given clang looks like:

tc-refptr.cc:8:12: error: no matching function call object of type 'const (lambda @       tc-refptr.cc:40:14)'     return m_t();            ^~~ tc-refptr.cc:44:27: note: in instantiation of member function 'wrapper<(lambda @       tc-refptr.cc:40:14)>::operator()' requested here   debugtype<decltype(cwfun())> df;                           ^ tc-refptr.cc:40:14: note: candidate function not viable: 'this' argument has type 'const       (lambda @ tc-refptr.cc:40:14)', method not marked const   auto fun = [foo]() mutable -> decltype(auto) { return foo(); }; 

code on coliru

first start partial_apply, in case written const-sensitive:

template<class f, class...args> struct partial_apply_t {   std::tuple<args...> args;   f f;   template<size_t...is, class self, class...extra>   static auto apply( self&& self, std::index_sequence<is...>, extra&&...extra )   -> decltype(     (std::forward<self>(self).f)(       std::get<is>(std::forward<self>(self).args)...,       std::declval<extra>()...     )   {     return std::forward<self>(self).f(       std::get<is>(std::forward<self>(self).args)...,       std::forward<extra>(extra)...     );   }   partial_apply_t(partial_apply_t const&)=default;   partial_apply_t(partial_apply_t&&)=default;   partial_apply_t& operator=(partial_apply_t const&)=default;   partial_apply_t& operator=(partial_apply_t&&)=default;   ~partial_apply_t()=default;   template<class f0, class...us,     class=std::enable_if_t<       std::is_convertible<std::tuple<f0, us...>, std::tuple<f, args...>>{}     >   >   partial_apply_t(f0&& f0, us&&...us):     f(std::forward<f0>(f0)),     args(std::forward<us>(us)...)   {}   // 3 operator() overloads.  more, lazy:   template<class...extra, class indexes=std::index_sequence_for<extra>>   auto operator()(extra&&...extra)const&   -> decltype( apply( std::declval<partial_apply_t const&>(), indexes{}, std::declval<extra>()... ) )   {     return apply( *this, indexes{}, std::forward<extra>(extra)... );   }   template<class...extra, class indexes=std::index_sequence_for<extra>>   auto operator()(extra&&...extra)&   -> decltype( apply( std::declval<partial_apply_t&>(), indexes{}, std::declval<extra>()... ) )   {     return apply( *this, indexes{}, std::forward<extra>(extra)... );   }   template<class...extra, class indexes=std::index_sequence_for<extra>>   auto operator()(extra&&...extra)&&   -> decltype( apply( std::declval<partial_apply_t&&>(), indexes{}, std::declval<extra>()... ) )   {     return apply( std::move(*this), indexes{}, std::forward<extra>(extra)... );   } }; template<class f, class... ts> partial_apply_t<std::decay_t<f>, std::decay_t<ts>...> partial_apply(f&& f, ts&&...ts) {   return {std::forward<f>(f), std::forward<ts>(ts)...}; } 

then use it:

auto fun = partial_apply(   [](auto&& foo) -> decltype(auto) { return foo(); },   foo ); 

now copy of foo stored in partial_apply, , @ point invoke it passed (in correct const-correctness) lambda. lambda gets different const-ness of foo depending on call context of fun.

other fact have typo above, other thing should handle std::ref , like, when expands args converts std::reference_wrapper references.

that shouldn't hard: reference_unwrapper passes non-reference-wrapped things through, , unwraps std::reference_wrappers.

alternatively, unwrap in partial_apply function, instead of decay_ting.


Comments

Popular posts from this blog

python - TypeError: start must be a integer -

c# - DevExpress RepositoryItemComboBox BackColor property ignored -

django - Creating multiple model instances in DRF3 -