{"id":924,"date":"2014-08-12T22:08:57","date_gmt":"2014-08-13T05:08:57","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=924"},"modified":"2015-06-30T21:18:20","modified_gmt":"2015-07-01T04:18:20","slug":"c-guru-question-followup","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=924","title":{"rendered":"C++ Guru Question &#8211; followup"},"content":{"rendered":"<p>(following on from <a href=\"https:\/\/www.elbeno.com\/blog\/?p=912\">C++ Guru Question<\/a>)<\/p>\n<p>There are a few reasons why the code before didn&#8217;t work: mainly<\/p>\n<p>a) C++ template argument deduction works one-way with a list of candidates, it&#8217;s not H-M type inference.<br \/>\nb) A C++ lambda is a thing with some internal type, not a std::function (although it can be assigned to one, that doesn&#8217;t matter for template type deduction).<\/p>\n<p>Anyway, a reasonable solution to this problem is to simplify the template argument matching to the function type, and use a simple function_traits template to take apart the function argument and return types.<\/p>\n<pre lang=\"cpp\">\r\ntemplate <typename T>\r\nstruct function_traits\r\n  : public function_traits<decltype(&#038;T::operator())>\r\n{};\r\n\r\ntemplate <typename R, typename A>\r\nstruct function_traits<R(A)>\r\n{\r\n  typedef R returnType;\r\n  typedef A argType;\r\n};\r\n\r\ntemplate <typename C, typename R, typename A>\r\nstruct function_traits<R(C::*)(A) const>\r\n  : public function_traits<R(A)>\r\n{};\r\n\r\ntemplate <typename T>\r\nstruct Foo\r\n{\r\n  T m_t;\r\n};\r\n\r\ntemplate <typename F>\r\ntypename function_traits<F>::returnType operator\/=(\r\n    Foo<typename function_traits<F>::argType> foo, const F& fn)\r\n{\r\n  return fn(foo.m_t);\r\n}\r\n\r\nvoid mystery()\r\n{\r\n  auto foo = Foo<int>{1};\r\n\r\n  \/\/ this works...\r\n  function<Foo<int>(int)> f1 = [] (int i) { return Foo<int>{i}; };\r\n  auto bar1 = foo \/= f1;\r\n\r\n  \/\/ this does too!\r\n  auto f2 = [] (int i) { return Foo<int>{i}; };\r\n  auto bar2 = foo \/= f2;\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>(following on from C++ Guru Question) There are a few reasons why the code before didn&#8217;t work: mainly a) C++ template argument deduction works one-way with a list of candidates, it&#8217;s not H-M type inference. b) A C++ lambda is a thing with some internal type, not a std::function (although&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22,8],"tags":[],"class_list":["post-924","post","type-post","status-publish","format-standard","hentry","category-cpp","category-programming"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/924","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=924"}],"version-history":[{"count":4,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/924\/revisions"}],"predecessor-version":[{"id":930,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/924\/revisions\/930"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=924"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=924"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=924"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}