Friday, 15 August 2014

c++ - Proper use of universal references -



c++ - Proper use of universal references -

before c++11, used write code this:

// little functions void dothingswitha(const a& a) { // stuff } void dothingswithb(const b& b) { // stuff } void dothingswithc(const c& c) { // stuff } // big function void dothingswithabc(const a& a, const b& b, const c& c) { // stuff dothingswitha(a); dothingswithb(b); dothingswithc(c); // stuff }

but now, move semantics, may become interesting (at to the lowest degree in cases) allow functions take rvalue references parameters , add together these overloads:

void dothingswitha(a&& a); void dothingswithb(b&& b); void dothingswithc(c&& c);

from gather, if want able phone call overloads within big function, need utilize perfect forwarding, may (it bit less readable, guess can ok naming convention template types):

template<typename tpla, typename tplb, typename tplc> void dothingswithabc(tpla&& a, tplb&& b, tplc&& c) { // stuff dothingswitha(std::forward<tpla>(a)); dothingswithb(std::forward<tplb>(b)); dothingswithc(std::forward<tplc>(c)); // stuff }

my problem this: doesn't mean if little functions have other overloads, become possible phone call big 1 parameters of types not intended?

i think may work prevent this:

template<typename tpla, typename tplb, typename tplc, class = typename std::enable_if<std::is_same<a, std::decay<tpla>::type>::value>::type, class = typename std::enable_if<std::is_same<b, std::decay<tplb>::type>::value>::type, class = typename std::enable_if<std::is_same<c, std::decay<tplc>::type>::value>::type> dothingswithabc(tpla&& a, tplb&& b, tplc&& c) { // stuff dothingswitha(std::forward<tpla>(a)); dothingswithb(std::forward<tplb>(b)); dothingswithc(std::forward<tplc>(c)); // stuff }

though not sure if not restrictive, have no thought of how behaves if seek phone call big functions types implicitly convertible a,b or c...

but... supposing works, have no other options? (i mean... it's not easy on eyes)

perfect forwarding when not know how info going consumed, because writing generic wrapper of 'user-supplied' data.

in simple procedural scheme describe above, 3 things concrete tasks.

that means know if benefit having movable source of info or not, , if create sense if have copy, , if move cheap.

if re-create makes sense, move faster, , move inexpensive (a mutual case), should take parameters by value , move out of them when store local copy.

this rule applies recursively function calls 3 sub functions.

if function not benefit moving, take const&.

if re-create not create sense, take rvalue reference (not universal reference) or value.

in case both able move and move remains expensive should consider perfect forwarding. noted above, happens when wrapping functions set 'user' of code base, move either really cheap, or expensive copy. have in intermediate or indeterminate stage of move efficiency perfect forwarding worthwhile.

there other uses perfect forwarding, such container mutators, more esoteric. example, backwards range mutator perfect forwards incoming range storage in order have reference lifetime extension work when chain multiple range mutators in c++11 style ranged-based for(:) loops.

madly perfect forwarding results in generated code bloat, slow builds, leaky implementations, , hard understand code.

c++ c++11 perfect-forwarding universal-reference forwarding-reference

No comments:

Post a Comment