title: How to type-cast as template member function parameter?
body: <p>I implemented the class template <code>writer</code>. The <code>writer</code> has template member variable <code>s_</code>. The type of <code>s_</code> is <code>Stream</code>. <code>writer</code> expects that <code>Stream</code> has a member function that can called with parameters <code>const char* buf</code> and <code>size_t len</code>.</p>
  
  <p>Here is the first version of <code>writer</code>:</p>
  
  <pre><code>// clang++ -Wconversion test.cpp
  
  #include &lt;cstddef&gt;
  #include &lt;ostream&gt;
  
  template &lt;class F&gt; struct size_arg_type;
  
  template &lt;typename Ret, typename Cls, typename T1, typename T2&gt;
  struct size_arg_type&lt;Ret (Cls::*)(T1, T2)&gt; {
      using type = T2;
  };
  
  template &lt;typename Stream&gt;
  struct writer {
      writer(Stream&amp; s):s_(s) {}
  
      void write(const char* buf, size_t len) {
          // The type of 2nd parameter depends on Stream
          s_.write(buf, len);
      }
  
      Stream&amp; s_;
  };
  
  struct user_stream1 {
      void write(const char*, size_t) {}
  };
  
  struct user_stream2 {
      void write(const char*, std::streamsize) {}
  };
  
  struct user_stream3 {
      void write(const char*, size_t) {}
      void write() {}
  };
  
  #include &lt;sstream&gt;
  
  int main() {
      {   // size_type is size_t
          user_stream1 s;
          writer w(s);
          char buf[] = "123";
          w.write(buf, sizeof(buf));
      }
      {   // size_type is std::streamsize
          user_stream2 s;
          writer w(s);
          char buf[] = "123";
          w.write(buf, sizeof(buf));
      }
  #if 1
      {   // size_type is size_t but has overloaded member function
          user_stream3 s;
          writer w(s);
          char buf[] = "123";
          w.write(buf, sizeof(buf));
      }
  #endif
      {   // size_type is std::streamsize return type is std::ostream&amp;
          std::stringstream s;
          writer w(s);
          char buf[] = "123";
          w.write(buf, sizeof(buf));
      }
  }
  </code></pre>
  
  <p>Running demo: <a href="https://wandbox.org/permlink/JtEHDG3plWxe4vwB" rel="nofollow noreferrer">https://wandbox.org/permlink/JtEHDG3plWxe4vwB</a></p>
  
  <p>If I set <code>-Wconversion</code> flags to clang++, I got the following warnings.</p>
  
  <pre><code>clang++ -std=c++17 -Wconversion test.cpp 
  test.cpp:18:23: warning: implicit conversion changes signedness: 'size_t' (aka 'unsigned long') to
        'std::streamsize' (aka 'long') [-Wsign-conversion]
          s_.write(buf, len);
             ~~~~~      ^~~
  test.cpp:50:11: note: in instantiation of member function 'writer&lt;user_stream2&gt;::write' requested here
          w.write(buf, sizeof(buf));
            ^
  test.cpp:18:23: warning: implicit conversion changes signedness: 'size_t' (aka 'unsigned long') to
        'std::streamsize' (aka 'long') [-Wsign-conversion]
          s_.write(buf, len);
             ~~~~~      ^~~
  test.cpp:64:11: note: in instantiation of member function 'writer&lt;std::__cxx11::basic_stringstream&lt;char&gt;
        &gt;::write' requested here
          w.write(buf, sizeof(buf));
            ^
  2 warnings generated.
  
  Compilation finished at Wed May  1 09:37:37
  </code></pre>
  
  <p>I tried to find a way to suppress the warnings without pragma.
  I came up with <code>static_cast</code> approach. In order to do <code>static_cast</code>, I need to know the 2nd parameter type.</p>
  
  <p>So I implemented some parameter type extractor:</p>
  
  <pre><code>// clang++ -std=c++17 -Wconversion test.cpp
  
  #include &lt;cstddef&gt;
  #include &lt;ostream&gt;
  
  template &lt;class F&gt; struct size_arg_type;
  
  template &lt;typename Ret, typename Cls, typename T1, typename T2&gt;
  struct size_arg_type&lt;Ret (Cls::*)(T1, T2)&gt; {
      using type = T2;
  };
  
  template &lt;typename Stream&gt;
  struct writer {
      writer(Stream&amp; s):s_(s) {}
  
      void write(const char* buf, size_t len) {
          write_impl(&amp;Stream::write, buf, len);
      }
  
      template &lt;typename Write&gt;
      void write_impl(Write, const char* buf, size_t len)
      {
          s_.write(buf, static_cast&lt;typename size_arg_type&lt;Write&gt;::type&gt;(len));
      }
  
      Stream&amp; s_;
  };
  
  struct user_stream1 {
      void write(const char*, size_t) {}
  };
  
  struct user_stream2 {
      void write(const char*, std::streamsize) {}
  };
  
  struct user_stream3 {
      void write(const char*, size_t) {}
      void write() {}
  };
  
  #include &lt;sstream&gt;
  
  int main() {
      {   // size_type is size_t
          user_stream1 s;
          writer w(s);
          char buf[] = "123";
          w.write(buf, sizeof(buf));
      }
      {   // size_type is std::streamsize
          user_stream2 s;
          writer w(s);
          char buf[] = "123";
          w.write(buf, sizeof(buf));
      }
  #if 1
      {   // size_type is size_t but has overloaded member function
          user_stream3 s;
          writer w(s);
          char buf[] = "123";
          w.write(buf, sizeof(buf));
      }
  #endif
      {   // size_type is std::streamsize return type is std::ostream&amp;
          std::stringstream s;
          writer w(s);
          char buf[] = "123";
          w.write(buf, sizeof(buf));
      }
  }
  </code></pre>
  
  <p>It works as I expected. However In the case <code>user_stream3</code> that has overloaded <code>write()</code> member function, compile error is happened.</p>
  
  <p>Running demo: <a href="https://wandbox.org/permlink/TDPlQ3nXzIKjSlhY" rel="nofollow noreferrer">https://wandbox.org/permlink/TDPlQ3nXzIKjSlhY</a></p>
  
  <p>In order to get specific overload of member functions, I need to know full member function pointer type. However, it is unpredictable.</p>
  
  <pre><code>    clang++ -std=c++17 -Wconversion test.cpp 
      test.cpp:18:9: error: no matching member function for call to 'write_impl'
              write_impl(&amp;Stream::write, buf, len);
              ^~~~~~~~~~
      test.cpp:63:11: note: in instantiation of member function 'writer&lt;user_stream3&gt;::write' requested here
              w.write(buf, sizeof(buf));
                ^
      test.cpp:22:10: note: candidate template ignored: couldn't infer template argument 'Write'
          void write_impl(Write, const char* buf, size_t len)
               ^
      1 error generated.
  
      Compilation exited abnormally with code 1 at Wed May  1 09:48:42
  </code></pre>
  
  <p>Is there any good way to know the size-type, or to suppress warning without pragma?</p>