title: customisation point for alias to std types
body: <p>Let's say I am writing some generic algorithm in <code>lib</code> namespace that calls a customisation point <code>my_func</code>.</p>
  <p>First attempt is using ADL for <code>my_func</code>
  one of the user wants to specialise <code>my_func</code> for his type, which is an alias to <code>std</code> type. Surely define it in his namespace won't work because ADL won't work for alias. Defining it in <code>std</code> namespace is not allowed by the standard. the only option left seems to define in the algorithm's namespace <code>lib</code>. But this doesn't work either if the end user includes the algorithm header before including the customisation header.</p>
  <pre><code>#include &lt;iostream&gt;
  #include &lt;array&gt;
  
  // my_algorithm.hpp
  namespace lib{
  
  template&lt;typename T&gt;
  void my_algorithm(const T&amp; t){
      my_func(t);
  }
  
  } // namespace lib
  
  // user1.hpp
  namespace user1{
  
  struct Foo1{
      // this is working as expected (ADL)
      friend void my_func(const Foo1&amp;){
          std::cout &lt;&lt; &quot;called user1's customisation\n&quot;;
      }
  };
  
  } // namespace user1
  
  // user2.hpp
  namespace user2{
  
  using Foo2 = std::array&lt;int,1&gt;;
  
  // this won't work because Foo2 is actually in std namespace
  void my_func(const Foo2&amp;){
          std::cout &lt;&lt; &quot;called user2's customisation\n&quot;;
  }
  
  } // namespace user2
  
  /* surely this isn't allowed
  namespace std{
  void my_func(const user2::Foo2&amp;){
          std::cout &lt;&lt; &quot;called user2's customisation\n&quot;;
  }
  } //namespace std
  */
  
  // another attempt to costomize in the algorithm's namespace
  // this won't work because my_func isn't seen before my_algorithm
  namespace lib{
      void my_func(const user2::Foo2&amp;){
          std::cout &lt;&lt; &quot;called user2's customisation\n&quot;;
      }
  }
  
  
  
  // main.cpp
  // #include &quot;algorithm.hpp&quot;
  // #include &quot;user1.hpp&quot;
  // #include &quot;user2.hpp&quot;
  int main(){
      lib::my_algorithm(user1::Foo1{});
      lib::my_algorithm(user2::Foo2{});
  }
  </code></pre>
  <p><a href="https://godbolt.org/z/bfdP8s" rel="nofollow noreferrer">https://godbolt.org/z/bfdP8s</a></p>
  <p>Second attempt is using niebloids for <code>my_func</code>, which has the same problem as ADL.</p>
  <p>Third attempt is using <code>tag_invoke</code>, which should have same problem as ADL, i.e.,</p>
  <ul>
  <li>customising in user namespace won't work because my type is an alias to <code>std</code> type</li>
  <li>customising in <code>std</code> isn't allowed</li>
  <li>customising in <code>lib</code> namespace depends on the order the header includes
  The first points seem to be true, but the last point isn't. This seems to work</li>
  </ul>
  <pre><code>#include &lt;iostream&gt;
  #include &lt;array&gt;
  
  // tag_invoke.hpp  overly simplified version
  namespace lib_ti{
  
  inline namespace tag_invoke_impl{
  
  inline constexpr struct tag_invoke_fn{
  
  template&lt;typename CP, typename... Args&gt;
  decltype(auto) operator()(CP cp, Args&amp;&amp;... args) const{
      return tag_invoke(cp, static_cast&lt;Args&amp;&amp;&gt;(args)...);
  }
  
  } tag_invoke{};
  
  } // namespace tag_invoke_impl
  } // namespace lib_to
  
  
  // my_algorithm.hpp
  
  // #include &quot;tag_invoke.hpp&quot;
  namespace lib{
  
  inline constexpr struct my_func_fn {
      
  template &lt;typename T&gt;
  void operator()(const T&amp; t) const{
      lib_ti::tag_invoke(*this, t);
  }
  
  } my_func{};
  
  
  template&lt;typename T&gt;
  void my_algorithm(const T&amp; t){
      my_func(t);
  }
  
  } // namespace lib
  
  // user1.hpp
  namespace user1{
  
  struct Foo1{
      // this is working as expected (ADL)
      friend void tag_invoke(lib::my_func_fn, const Foo1&amp;){
          std::cout &lt;&lt; &quot;called user1's customisation\n&quot;;
      }
  };
  
  } // namespace user1
  
  // user2.hpp
  namespace user2{
  
  using Foo2 = std::array&lt;int,1&gt;;
  
  // this won't work because Foo2 is actually in std namespace
  void tag_invoke(lib::my_func_fn, const Foo2&amp;){
          std::cout &lt;&lt; &quot;called user2's customisation\n&quot;;
  }
  
  } // namespace user2
  
  /* surely this isn't allowed
  namespace std{
  void tag_invoke(lib::my_func_fn, const user2::Foo2&amp;){
          std::cout &lt;&lt; &quot;called user2's customisation\n&quot;;
  }
  } //namespace std
  */
  
  // another attempt to customise in the algorithm's namespace
  // In ADL case, this does not work. But in this case, it seems to work. why?
  namespace lib{
      void tag_invoke(lib::my_func_fn, const user2::Foo2&amp;){
          std::cout &lt;&lt; &quot;called user2's customisation\n&quot;;
      }
  }
  
  
  
  // main.cpp
  int main(){
      lib::my_algorithm(user1::Foo1{});
      lib::my_algorithm(user2::Foo2{});
  }
  </code></pre>
  <p><a href="https://godbolt.org/z/hsKbKE" rel="nofollow noreferrer">https://godbolt.org/z/hsKbKE</a></p>
  <p><strong>Why does this not have the same problem as the First one (raw ADL)?</strong></p>
  <p>Forth attempt is using template specialisation, which seems to work normally as expected</p>
  <pre><code>#include &lt;iostream&gt;
  #include &lt;array&gt;
  
  
  
  
  // my_algorithm.hpp
  
  namespace lib{
  
  template&lt;typename T, typename = void&gt;
  struct my_func_impl{
      //void static apply(const T&amp;) = delete;
  };
  
  inline constexpr struct my_func_fn {
      
  template &lt;typename T&gt;
  void operator()(const T&amp; t) const{
      using impl = my_func_impl&lt;std::decay_t&lt;T&gt;&gt;;
      impl::apply(t);
  }
  
  } my_func{};
  
  
  template&lt;typename T&gt;
  void my_algorithm(const T&amp; t){
      my_func(t);
  }
  
  } // namespace lib
  
  // user1.hpp
  namespace user1{
  
  struct Foo1{};
  
  } // namespace user1
  
  namespace lib{
  
  template&lt;&gt;
  struct my_func_impl&lt;user1::Foo1&gt;{
      void static apply(const user1::Foo1&amp;){
          std::cout &lt;&lt; &quot;called user1's customisation\n&quot;;
      }
  };
  
  } //namespace lib
  
  
  
  // user2.hpp
  namespace user2{
  
  using Foo2 = std::array&lt;int,1&gt;;
  
  } // namespace user2
  
  namespace lib{
  
  template&lt;&gt;
  struct my_func_impl&lt;user2::Foo2&gt;{
      void static apply(const user2::Foo2&amp;){
          std::cout &lt;&lt; &quot;called user2's customisation\n&quot;;
      }
  };
  
  }
  
  
  
  // main.cpp
  int main(){
      lib::my_algorithm(user1::Foo1{});
      lib::my_algorithm(user2::Foo2{});
  }
  </code></pre>
  <p><a href="https://godbolt.org/z/r71x6c" rel="nofollow noreferrer">https://godbolt.org/z/r71x6c</a></p>
  <hr />
  <p>What is the best way to write generic algorithms and customisation points and allow clients to customise for aliases for std types?</p>