title: Is there a way to improve this Delegate<void(int&)>::Bind<TestStruct&, &TestStruct::somefunction>(testStruct, value) syntax?
body: <p>I am trying to implement a Delegate type that would work with generic callbacks and work in presence of an overload set.</p>
  <p>For simplification here is an excerpt of the class with the bind method implemented as static function to simplify the problem.</p>
  <pre><code>template &lt;typename Signature&gt;
  class Delegate;
  
  template &lt;typename Ret, typename... Args&gt;
  struct Delegate&lt;Ret(Args...)&gt; {
      using Trampoline_T = Ret (*)(void*, Args&amp;&amp;...);
      using TrampolineConst_T = Ret (*)(const void*, Args&amp;&amp;...);
  
      using Function_Sig = Ret(Args...);
      using Function_Ptr = std::add_pointer_t&lt;Function_Sig&gt;;
  
      template &lt;typename Instance_T&gt;
      using MemberFunction_Sig = Ret(std::remove_reference_t&lt;Instance_T&gt;&amp;,
                                     Args...);
      template &lt;typename Instance_T&gt;
      using MemberFunction_Ptr =
          Ret (std::remove_reference_t&lt;Instance_T&gt;::*)(Args...);
      template &lt;typename Instance_T&gt;
      using MemberFunctionConst_Ptr =
          Ret (std::remove_reference_t&lt;Instance_T&gt;::*)(Args...) const;
      template &lt;typename Instance_T&gt;
      using MemberFunctionConstOrNot_Ptr =
          std::conditional_t&lt;std::is_const_v&lt;std::remove_reference_t&lt;Instance_T&gt;&gt;,
                             MemberFunctionConst_Ptr&lt;Instance_T&gt;,
                             MemberFunction_Ptr&lt;Instance_T&gt;&gt;;
  
      template &lt;typename Instance_T, MemberFunctionConstOrNot_Ptr&lt;Instance_T&gt; fct, typename T&gt;
      static void Bind(T&amp;&amp; instance, auto&amp;&amp; value) {
  
          if constexpr (!std::is_const_v&lt;std::remove_reference_t&lt;Instance_T&gt;&gt;) {
              Trampoline_T trampoline = [](void* storage, Args&amp;&amp;... args) -&gt; Ret {
                  std::invoke(
                      fct,
                      *reinterpret_cast&lt;std::remove_reference_t&lt;Instance_T&gt;*&gt;(
                          storage),
                      std::forward&lt;decltype(args)&gt;(args)...);
              };
              trampoline(&amp;instance, value);
          } else {
              TrampolineConst_T trampoline = [](const void* storage,
                                                Args&amp;&amp;... args) -&gt; Ret {
                  std::invoke(
                      fct,
                      *reinterpret_cast&lt;std::remove_reference_t&lt;Instance_T&gt;*&gt;(
                          storage),
                      std::forward&lt;decltype(args)&gt;(args)...);
              };
              trampoline(&amp;instance, value);
          }
      }
  
      template &lt;typename Instance_T&gt;
      static void Bind(Instance_T&amp;&amp; instance, auto&amp;&amp; value) {
          if constexpr (!std::is_const_v&lt;std::remove_reference_t&lt;Instance_T&gt;&gt;) {
              Trampoline_T trampoline = [](void* storage, Args&amp;&amp;... args) -&gt; Ret {
                  std::invoke(
                      *reinterpret_cast&lt;std::remove_reference_t&lt;Instance_T&gt;*&gt;(
                          storage),
                      std::forward&lt;decltype(args)&gt;(args)...);
              };
              trampoline(&amp;instance, value);
          } else {
              TrampolineConst_T trampoline = [](const void* storage,
                                                Args&amp;&amp;... args) -&gt; Ret {
                  std::invoke(
                      *reinterpret_cast&lt;std::remove_reference_t&lt;Instance_T&gt;*&gt;(
                          storage),
                      std::forward&lt;decltype(args)&gt;(args)...);
              };
              trampoline(&amp;instance, value);
          }
      }
  };
  </code></pre>
  <p>Now to use such a type with an object Test</p>
  <pre><code>class TestStruct {
     public:
      constexpr static int m_staticValue = 42;
      uint8_t m_value = m_staticValue;
  
      void somefunctionGeneric(auto&amp; value) {
          std::cout &lt;&lt; &quot;somefunctionGeneric &quot; &lt;&lt; value &lt;&lt; &quot;\n&quot;;
      }
      void somefunctionGeneric(auto&amp; value) const {
          std::cout &lt;&lt; &quot;somefunctionGeneric const &quot; &lt;&lt; value + 1 &lt;&lt; &quot;\n&quot;;
      }
      void somefunction(int&amp; value) {
          std::cout &lt;&lt; &quot;somefunction &quot; &lt;&lt; value &lt;&lt; &quot;\n&quot;;
      }
      void somefunction(int&amp; value) const {
          std::cout &lt;&lt; &quot;somefunction const &quot; &lt;&lt; value + 1 &lt;&lt; &quot;\n&quot;;
      }
  
      void operator()(auto&amp; value) {
          std::cout &lt;&lt; &quot;operator()(auto&amp;) &quot; &lt;&lt; value &lt;&lt; &quot;\n&quot;;
      }
      void operator()(auto&amp; value) const {
          std::cout &lt;&lt; &quot;operator()(auto&amp;) const &quot; &lt;&lt; value + 1 &lt;&lt; &quot;\n&quot;;
      }
      void operator()(int&amp; value) {
          std::cout &lt;&lt; &quot;operator()(int&amp;) &quot; &lt;&lt; value &lt;&lt; &quot;\n&quot;;
      }
      void operator()(int&amp; value) const {
          std::cout &lt;&lt; &quot;operator()(int&amp;) const &quot; &lt;&lt; value + 1 &lt;&lt; &quot;\n&quot;;
      }
  };
  </code></pre>
  <p>You would use it this way:</p>
  <pre><code>int value = 42;
  double valueDouble = 42;
  TestStruct testStruct;
  Delegate&lt;void(int&amp;)&gt;::Bind&lt;TestStruct&amp;, &amp;TestStruct::somefunction&gt;(testStruct, value);
  Delegate&lt;void(double&amp;)&gt;::Bind&lt;TestStruct&amp;,&amp;TestStruct::somefunctionGeneric&lt;double&gt;&gt;(testStruct, valueDouble);
  
  Delegate&lt;void(int&amp;)&gt;::Bind(testStruct, value);
  Delegate&lt;void(double&amp;)&gt;::Bind(testStruct, valueDouble);
  
  const TestStruct testStructConst;
  Delegate&lt;void(int&amp;)&gt;::Bind&lt;const TestStruct&amp;, &amp;TestStruct::somefunction&gt;(testStructConst, value);
  Delegate&lt;void(double&amp;)&gt;::Bind&lt;const TestStruct&amp;, &amp;TestStruct::somefunctionGeneric&lt;double&gt;&gt;(testStructConst, valueDouble);
  
  Delegate&lt;void(int&amp;)&gt;::Bind(testStructConst, value);
  Delegate&lt;void(double&amp;)&gt;::Bind(testStructConst, valueDouble);
  </code></pre>
  <p><a href="https://godbolt.org/z/7v7h6MndT" rel="nofollow noreferrer">Compiler explorer code</a></p>
  <p>I would like to improve the Bind call syntax. I have to pass the class and the function as template. I feel like there is some trick to improve that. Like using a class template to deduce the types. It might not be possible and that if know it can't be improved with c++20 I will gladly accept this answer.</p>
  <p>Requirements:
  The function has to be a template parameter to be captured in the trampoline lambda. The trampoline lambda has to be convertible to function pointer.
  It has to work with overload set function like: <code>void somefunction(int&amp; value)</code> and <code>void somefunction(int&amp; value) const</code>
  The function should be able to be a template const or not.
  Lambda should be supported.
  And please don't suggest std::function, this is what I have is 10% more performant when the function is inlinable.</p>
  <p>It works at the moment, but I am pretty shure I saw techniques to improve this <code>Delegate&lt;void(int&amp;)&gt;::Bind&lt;TestStruct&amp;, &amp;TestStruct::somefunction&gt;(testStruct, value);</code> I just can't figure them out at the moment.</p>
  <p>Thank you very much</p>
  <p>Note: Yes the value is passed in the Bind fucntion this is just for ilustration and because the bind function are static. In my code there is a Bind and an invoke function.</p>