<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Fri, Dec 30, 2016 at 2:08 AM Piotr Padlewski via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="gmail_msg">Thanks for very accurate responses.<div class="gmail_msg">- I totally agree what Dave and Chandler said about explicit and implicit operations, this is what I meant my first email.</div><div class="gmail_msg">  I believe there are places like </div><div class="gmail_msg">    v.emplace_back(A, B);</div><div class="gmail_msg">  istead of</div><div class="gmail_msg">    v.push_back(make_pair(A, B));b</div><div class="gmail_msg">  That can make code simpler.</div></div></blockquote><div><br></div><div>Do you have examples? The only ones i can come up with are the ones where the push_back variant literally can't compile because the type isn't movable.</div><div><br></div><div>Perhaps it would be useful to break down categories of can happen here...</div><div><br></div><div>Case 1: there is one object already -- this is a *conversion* of a type.</div><div>- If the author of the conversion made it *implicit*, then 'v.push_back(x)' just works.</div><div>- If the author of the conversion made it *explicit* I would like to see the name of the type explicitly: 'v.push_back(T(x))'.</div><div><br></div><div>Case 2a: There is a collection of objects that are being composed into an aggregate. We don't have any interesting logic in the constructor, it takes an initializer list.</div><div>- This should work with 'v.push_back({a, b, c})'</div><div>- If it doesn't today, we can fix the type's constructors so that it does.</div><div>- Using 'emplace_back' doesn't help much -- you still need {}s to form the std::initializer_list in many cases. Pair and tuple are somewhat unusual in not requiring them.</div><div><br></div><div>Case 2b: A specific constructor needs to be called with an argument list. These arguments are not merely being aggregated but are inputs to a constructor that contains logic.</div><div>- This is analogous to a case called out w.r.t. '{...}' syntax in the coding standards[1]</div><div>- Similar to that rule, I would like to see a *call to the constructor* rather than hiding it behind 'emplace_back' as this is a function with interesting logic.</div><div>- That means i would write T(a, b, c) anyways, and 'v.push_back(T(a, b, c))' works.</div><div><br></div><div>[1]: <a href="http://llvm.org/docs/CodingStandards.html#do-not-use-braced-initializer-lists-to-call-a-constructor">http://llvm.org/docs/CodingStandards.html#do-not-use-braced-initializer-lists-to-call-a-constructor</a></div><div><br></div><div>Case 3: Passing objects of type 'T' through 'push_back' fails to compile because they cannot be copied or moved.</div><div>- You *must* use 'emplace_back' here. No argument (obviously).</div><div><br></div><div>My experience with LLVM code and other codebases is that case 3 should be extremely rare. The intersection of "types that cannot be moved or copied" and "types that you put into containers" is typically small.</div><div><br></div><div><br></div><div>Anyways, I don't disagree with this point with a tiny fix:</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="gmail_msg"><div class="gmail_msg"> I think in cases like this we can leave it for judgement of contributor.</div></div></blockquote><div>*or reviewer*. ;]</div><div><br></div><div>I continue to think exceptions can be made in rare cases when folks have good reasons. But I expect this to be quite rare. =]</div></div></div>