title: Is there a way to check if a class is convertible to some template instantiation?
body: <h2>The question</h2>
  <p>Here some code</p>
  <pre class="lang-cpp prettyprint-override"><code>struct Base
  {
      int SomeMethod(const Base&amp;);
      template &lt;class T&gt; int SomeMethod(const T&amp;);
  };
  
  template &lt;class Tag&gt; struct Derived : Base
  {
      using Base::SomeMethod;
      int SomeMethod(const Derived&amp;);
      template &lt;class OtherTag&gt; std::enable_if_t&lt;!std::is_same_v&lt;Tag, OtherTag&gt;&gt; SomeMethod(Derived&lt;OtherTag&gt;) = delete;
  };
  
  struct tag {};
  struct another_tag {};
  
  struct ImplicitOpToAnotherTagInstantiation { operator Derived&lt;another_tag&gt;() const; };
  </code></pre>
  <p>Is there something (<code>Derived::SomeMethod</code> overload) that i can write in <code>Derived</code> without touching the <code>Base</code>, that will cause a compiler error in the next code?</p>
  <pre class="lang-cpp prettyprint-override"><code>Derived&lt;tag&gt;{}.SomeMethod(ImplicitOpToAnotherTagInstantiation {});
  </code></pre>
  <p>Next code should be correct</p>
  <pre class="lang-cpp prettyprint-override"><code>struct ImplicitOpToBase { operator Base() const; };
  
  Derived&lt;tag&gt;{}.SomeMethod(Derived&lt;tag&gt;{});
  Derived&lt;tag&gt;{}.SomeMethod(Base{});
  Derived&lt;tag&gt;{}.SomeMethod(ImplicitOpToBase{});
  // Derived&lt;tag&gt;{}.SomeMethod(Derived&lt;another_tag&gt;{}); compiler error!
  </code></pre>
  <h2>What have I tried</h2>
  <ul>
  <li>First thought was to do something like this:</li>
  </ul>
  <pre class="lang-cpp prettyprint-override"><code>template &lt;class Tag&gt; struct Derived : Base
  {
      using Base::SomeMethod;
      int SomeMethod(const Derived&amp;);
      template &lt;class OtherTag&gt; std::enable_if_t&lt;!std::is_same_v&lt;Tag, OtherTag&gt;&gt; SomeMethod(Derived&lt;OtherTag&gt;) = delete;
      template &lt;class T, class OtherTag&gt; std::enable_if_t&lt;!std::is_same&lt;Tag, OtherTag&gt; &amp;&amp; std::is_convertible&lt;Tag, Derived&lt;OtherTag&gt;&gt;&gt; SomeMethod(T) = delete;
  };
  </code></pre>
  <p>But it doesn't work because there is no way for compiler to deduce <code>OtherTag</code>, without explicit instantiation like this</p>
  <pre class="lang-cpp prettyprint-override"><code>Derived&lt;tag&gt;{}.SomeMethod&lt;ImplicitOpToAnotherTagInstantiation, another_tag&gt;(); // error: deleted function!
  </code></pre>
  <ul>
  <li>Second thought:</li>
  </ul>
  <pre class="lang-cpp prettyprint-override"><code>template &lt;class Tag&gt; struct Derived : Base
  {
      using Base::SomeMethod;
      int SomeMethod(const Derived&amp;);
      template &lt;class OtherTag&gt; std::enable_if_t&lt;!std::is_same_v&lt;Tag, OtherTag&gt;&gt; SomeMethod(Derived&lt;OtherTag&gt;) = delete;
      template &lt;class T&gt; std::enable_if_t&lt;!std::is_same&lt;T, Derived&gt; &amp;&amp; std::is_convertible&lt;T, Base&gt;&gt; SomeMethod(T) = delete;
  };
  </code></pre>
  <p>But next code results in compiler error, when shouldn't:</p>
  <pre class="lang-cpp prettyprint-override"><code>Derived&lt;tag&gt;{}.SomeMethod(ImplicitOpToBase{});
  </code></pre>
  <h2>Main usage</h2>
  <p>I am trying to create some kind of a strong typedef for <code>std::string</code> where <code>Base</code> is <code>std::string</code>, <code>Derived</code> is my <code>TaggedString</code>, <code>SomeMethod</code> is <code>std::string::assign</code>. I want to disable <code>assign</code> method with types of another tag and I have some difficulties explained in the question. For the sake of the reader i am omitting the fact, that <code>TaggedString</code> is implicitly convertible to <code>std::string_view</code>.</p>
  <pre class="lang-cpp prettyprint-override"><code>template &lt;class Tag&gt; struct TaggedString : std::string
  {
      using std::string::assign;
      TaggedString&amp; assign(const TaggedString&amp; other) { std::string::assign(other); return *this; }
      template &lt;class OtherTag&gt; std::enable_if_t&lt;!std::is_same_v&lt;Tag, OtherTag&gt;&gt; assign(TaggedString&lt;OtherTag&gt;) = delete;
  };
  </code></pre>
  <p><a href="https://godbolt.org/z/5nocben88" rel="nofollow noreferrer">Here</a> is something to play with.</p>