{"id":20705,"date":"2018-08-29T08:29:06","date_gmt":"2018-08-29T15:29:06","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vcblog\/?p=20705"},"modified":"2019-02-18T17:47:47","modified_gmt":"2019-02-18T17:47:47","slug":"qa-how-to-specialize-stdsort-by-binding-the-comparison-function","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/qa-how-to-specialize-stdsort-by-binding-the-comparison-function\/","title":{"rendered":"Q&amp;A: How to specialize std::sort by binding the comparison function"},"content":{"rendered":"<p><em>This post is part of a regular series of posts where the C++ product team here at Microsoft and other guests answer questions we have received from customers. The questions can be about anything C++ related: Visual C++, the standard language and library, the C++ standards committee, isocpp.org, CppCon, etc. Today&#8217;s Q&amp;A is by Herb Sutter.<\/em><\/p>\n<h3>Question<\/h3>\n<p>A reader recently asked: I am trying to specialize <strong>std::sort<\/strong> by binding the comparison function.\nI first tried:<\/p>\n<pre class=\"lang:default decode:true \">auto sort_down = bind(sort&lt;&gt;,_1,_2,[](int x, int y){return x &gt; y;});<\/pre>\n<p>It couldn\u2019t infer the parameter types. So then I tried:<\/p>\n<pre class=\"decode:true\">auto sort_down = bind(sort&lt;vector&lt;int&gt;::iterator,function&lt;int(int)&gt;&gt;,\r\n                      _1,_2,[](int x, int y){return x &gt; y;});<\/pre>\n<p>Is there a straightforward way to do this?\nAnother example:<\/p>\n<pre class=\"decode:true\">auto f = bind(plus&lt;&gt;(), _1, 1)<\/pre>\n<p>Here <strong>bind<\/strong> has no trouble deducing the template arguments in this case, but when I use a function template for the original callable, it&#8217;s not so happy. Just wanting to be consistent with this usage.<\/p>\n<h3>Answer<\/h3>\n<p>First, the last sentence is excellent: We should definitely be aiming for a general consistent answer where possible so we can spell the same thing the same way throughout our code.<\/p>\n<p>In questions about <strong>bind<\/strong>ers, the usual answer is to use a lambda function directly instead \u2013 and usually a generic lambda is the simplest and most flexible. A lambda additionally lets you more directly express how to take its parameters when it\u2019s invoked \u2013 by value, by reference, by const, and so forth, instead of resorting to things like <strong>std::ref<\/strong> as we do when we use binders.<\/p>\n<p>For the second example, you can write\u00a0<strong>f<\/strong>\u00a0as a named lambda this way:<\/p>\n<pre class=\"lang:default decode:true\">auto f = [](const auto&amp; x){ return x+1; };<\/pre>\n<p>For the first example, you can write <strong>sort_down<\/strong> as a named lambda like this:<\/p>\n<pre class=\"\">auto sort_down = [](auto a, auto b){ return sort(a, b, [](int x, int y){return x &gt; y;}); };<\/pre>\n<p>Note the way to give a name to a lambda: assign it to an <strong>auto<\/strong> variable, which you can give any name you like. In this case I take <strong>a<\/strong> and <strong>b<\/strong> by value because we know they\u2019re intended to be iterators which are supposed to be cheap to copy.<\/p>\n<p>The nice thing about lambdas is they allow exactly what you asked for: consistency. To be consistent, code should use lambdas exclusively, never <strong>bind<\/strong>. As of C++14, which added generic lambdas, lambdas can now do everything binders can do and more, so there is never a reason to use the binders anymore.<\/p>\n<p>Note that the old binders <strong>bind1st<\/strong> and <strong>bind2nd<\/strong> were deprecated in C++11 and removed in C++17. Granted, we have not yet deprecated or removed <strong>std::bind<\/strong> itself, but I wouldn\u2019t be surprised to see that removed too. Although <strong>bind<\/strong> can be convenient and it\u2019s not wrong to use it, there is no reason I know of to use it in new code that is not now covered by lambdas, and since lambdas can do things that binders cannot, we should encourage and use lambdas consistently.<\/p>\n<p>As a side point, notice that the \u201cgreater than\u201d comparison lambda<\/p>\n<pre class=\"decode:true\">[](int x, int y){return x &gt; y;}<\/pre>\n<p>expects integer values only, and because of the glories of the C integer types it can give the wrong results because of truncating (e.g., if passed a <strong>long long<\/strong>) and\/or sign conversion (e.g., a 32-bit unsigned 3,000,000,000 is greater than 5, but when converted to signed is less than 5). It would be better written as<\/p>\n<pre class=\"decode:true\">[](const auto&amp; x, const auto&amp; y){return x &gt; y;}<\/pre>\n<p>or in this case<\/p>\n<pre class=\"decode:true\">std::greater&lt;&gt;{}<\/pre>\n<p>Thanks to Stephan Lavavej for comments on this answer.<\/p>\n<h3>Your questions?<\/h3>\n<p><em>If you have any question about C++ in general, please comment about it below. Someone in the community may answer it, or someone on our team may consider it for a future blog post. If instead your question is about support for a Microsoft product, you can provide feedback via <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/ide\/how-to-report-a-problem-with-visual-studio-2017\">Help &gt; Report A Problem<\/a> in the product, or via <a href=\"https:\/\/developercommunity.visualstudio.com\/topics\/C%2B%2B.html\">Developer Community<\/a>.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post is part of a regular series of posts where the C++ product team here at Microsoft and other guests answer questions we have received from customers. The questions can be about anything C++ related: Visual C++, the standard language and library, the C++ standards committee, isocpp.org, CppCon, etc. Today&#8217;s Q&amp;A is by Herb [&hellip;]<\/p>\n","protected":false},"author":626,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-20705","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus"],"acf":[],"blog_post_summary":"<p>This post is part of a regular series of posts where the C++ product team here at Microsoft and other guests answer questions we have received from customers. The questions can be about anything C++ related: Visual C++, the standard language and library, the C++ standards committee, isocpp.org, CppCon, etc. Today&#8217;s Q&amp;A is by Herb [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/20705","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/626"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=20705"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/20705\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=20705"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=20705"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=20705"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}