Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>It isn't too easy and in C++03 it isn't in general possible. If you use <code>int*</code> and <code>int*</code> for <code>op&lt;&lt;</code> for example, you will get a hard error at compile time. So for non-class types, you need to filter out the types that the Standard forbids. </p> <p>For <code>op+</code> I once wrote such a thing for the kicks. Note that I'm using <code>C</code> headers, because I needed to test the code with the <code>clang</code> compiler too, which at that time didn't support my C++ headers:</p> <pre><code>#include &lt;stddef.h&gt; #include &lt;stdio.h&gt; namespace detail { struct any { template&lt;typename T&gt; any(T const&amp;); }; struct tag { char c[2]; }; int operator,(detail::tag, detail::tag); template&lt;typename T&gt; void operator,(detail::tag, T const&amp;); char operator,(int, detail::tag); } namespace fallback { detail::tag operator+(detail::any const&amp;, detail::any const&amp;); } namespace detail { template&lt;typename T&gt; struct is_class { typedef char yes[1]; typedef char no[2]; template&lt;typename U&gt; static yes &amp;check(int U::*); template&lt;typename U&gt; static no &amp;check(...); static bool const value = sizeof check&lt;T&gt;(0) == 1; }; template&lt;typename T&gt; struct is_pointer { typedef T pointee; static bool const value = false; }; template&lt;typename T&gt; struct is_pointer&lt;T*&gt; { typedef T pointee; static bool const value = true; }; template&lt;typename T, typename U&gt; struct is_same { static bool const value = false; }; template&lt;typename T&gt; struct is_same&lt;T, T&gt; { static bool const value = true; }; template&lt;typename T&gt; struct is_incomplete_array { static bool const value = false; }; template&lt;typename T&gt; struct is_incomplete_array&lt;T[]&gt; { static bool const value = true; }; template&lt;typename T&gt; struct is_reference { typedef T referee; static bool const value = false; }; template&lt;typename T&gt; struct is_reference&lt;T&amp;&gt; { typedef T referee; static bool const value = true; }; // is_fn checks whether T is a function type template&lt;typename T&gt; struct is_fn { typedef char yes[1]; typedef char no[2]; template&lt;typename U&gt; static no &amp;check(U(*)[1]); template&lt;typename U&gt; static yes &amp;check(...); // T not void, not class-type, not U[], U&amp; and T[] invalid // =&gt; T is function type static bool const value = !is_same&lt;T const volatile, void&gt;::value &amp;&amp; !is_class&lt;T&gt;::value &amp;&amp; !is_incomplete_array&lt;T&gt;::value &amp;&amp; !is_reference&lt;T&gt;::value &amp;&amp; (sizeof check&lt;T&gt;(0) == 1); }; template&lt;typename T, bool = is_fn&lt;T&gt;::value&gt; struct mod_ty { typedef T type; }; template&lt;typename T&gt; struct mod_ty&lt;T, true&gt; { typedef T *type; }; template&lt;typename T&gt; struct mod_ty&lt;T[], false&gt; { typedef T *type; }; template&lt;typename T, size_t N&gt; struct mod_ty&lt;T[N], false&gt; { typedef T *type; }; // Standard says about built-in +: // // For addition, either both operands shall have arithmetic or enumeration type, // or one operand shall be a pointer to a completely defined object type and // the other shall have integral or enumeration type. template&lt;typename T&gt; struct Ty; // one particular type struct P; // pointer struct Nc; // anything nonclass struct A; // anything struct Fn; // function pointer // matches category to type template&lt;typename C, typename T, bool = is_pointer&lt;T&gt;::value, bool = !is_class&lt;T&gt;::value, bool = is_fn&lt;typename is_pointer&lt;T&gt;::pointee&gt;::value&gt; struct match { static bool const value = false; }; // one particular type template&lt;typename T, bool P, bool Nc, bool Fn&gt; struct match&lt;Ty&lt;T const volatile&gt;, T, P, Nc, Fn&gt; { static bool const value = false; }; // pointer template&lt;typename T, bool F&gt; struct match&lt;P, T, true, true, F&gt; { static bool const value = true; }; // anything nonclass template&lt;typename T, bool P, bool Fn&gt; struct match&lt;Nc, T, P, true, Fn&gt; { static bool const value = true; }; // anything template&lt;typename T, bool P, bool Nc, bool Fn&gt; struct match&lt;A, T, P, Nc, Fn&gt; { static bool const value = true; }; // function pointer template&lt;typename T&gt; struct match&lt;Fn, T, true, true, true&gt; { static bool const value = true; }; // one invalid combination template&lt;typename A, typename B&gt; struct inv; // a list of invalid combinations, terminated by B = void template&lt;typename A, typename B&gt; struct invs; // T[] &lt;=&gt; T[N] =&gt; T* // void() =&gt; void(*)() // T&amp; =&gt; T // trying to find all invalid combinations // for built-in op+ typedef invs&lt; inv&lt;Ty&lt;float const volatile&gt;, P&gt;, invs&lt; inv&lt;Ty&lt;double const volatile&gt;, P&gt;, invs&lt; inv&lt;Ty&lt;long double const volatile&gt;, P&gt;, invs&lt; inv&lt;Ty&lt;void * const volatile&gt;, Nc&gt;, invs&lt; inv&lt;Ty&lt;void const* const volatile&gt;, Nc&gt;, invs&lt; inv&lt;Ty&lt;void volatile* const volatile&gt;, Nc&gt;, invs&lt; inv&lt;Ty&lt;void const volatile* const volatile&gt;, Nc&gt;, invs&lt; inv&lt;Fn, Nc&gt;, invs&lt; inv&lt;Ty&lt;void const volatile&gt;, A&gt;, invs&lt; inv&lt;P, P&gt;, void &gt; &gt; &gt; &gt; &gt; &gt; &gt; &gt; &gt; &gt; invalid_list; // match condition: only when ECond&lt;true&gt; is passed by specialization, // then it will be selected. template&lt;bool&gt; struct ECond; template&lt;typename L, typename T, typename U, typename = ECond&lt;true&gt; &gt; struct found_impl; // this one will first modify the input types to be plain pointers // instead of array or function types. template&lt;typename L, typename T, typename U&gt; struct found : found_impl&lt;L, typename mod_ty&lt; typename is_reference&lt;T&gt;::referee&gt;::type, typename mod_ty&lt; typename is_reference&lt;U&gt;::referee&gt;::type&gt; { }; // match was found. template&lt;typename F, typename B, typename R, typename T, typename U&gt; struct found_impl&lt;invs&lt;inv&lt;F, B&gt;, R&gt;, T, U, ECond&lt;(match&lt;F, T&gt;::value &amp;&amp; match&lt;B, U&gt;::value) || (match&lt;B, T&gt;::value &amp;&amp; match&lt;F, U&gt;::value)&gt; &gt; { static bool const value = true; }; // recurse (notice this is less specialized than the previous specialization) template&lt;typename H, typename R, typename T, typename U, typename Ec&gt; struct found_impl&lt; invs&lt;H, R&gt;, T, U, Ec &gt; : found_impl&lt;R, T, U&gt; { }; // we hit the end and found nothing template&lt;typename T, typename U, typename Ec&gt; struct found_impl&lt; void, T, U, Ec &gt; { static bool const value = false; }; using namespace fallback; template&lt;typename T, typename U, bool found_invalid = found&lt;invalid_list, T, U&gt;::value&gt; struct is_addable { static T t; static U u; static bool const value = sizeof (detail::tag(), (t+u), detail::tag()) != 1; }; template&lt;typename T, typename U&gt; struct is_addable&lt;T, U, true&gt; { static bool const value = false; }; } template&lt;typename T, typename U&gt; struct is_addable { static bool const value = detail::is_addable&lt;T, U&gt;::value; }; </code></pre> <p>Of course, it's very important to do tests afterwards</p> <pre><code>// this one can be added struct test { test operator+(test) { return(*this); } }; // this one cannot be added struct nono { }; // this fails because of an ambiguity, because there is a comma // operator taking a variable parameter on its left hand side. struct fails { fails operator+(fails); }; template&lt;typename T&gt; void operator,(T const&amp;, fails); int main() { printf("%d\n", is_addable&lt;test, test&gt;::value); printf("%d\n", is_addable&lt;int, float&gt;::value); printf("%d\n", is_addable&lt;nono, nono&gt;::value); printf("%d\n", is_addable&lt;int*, int&gt;::value); printf("%d\n", is_addable&lt;int[1], int&gt;::value); printf("%d\n", is_addable&lt;int[1], float[2]&gt;::value); printf("%d\n", is_addable&lt;int*, float*&gt;::value); printf("%d\n", is_addable&lt;void*, float&gt;::value); printf("%d\n", is_addable&lt;void, int&gt;::value); printf("%d\n", is_addable&lt;void(), int&gt;::value); printf("%d\n", is_addable&lt;int, void(**)()&gt;::value); printf("%d\n", is_addable&lt;float*&amp;, int*&amp;&gt;::value); } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload