Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I found the answer to my own question.</p> <p><code>returns_reference</code> returns a type with size > 1 if the return type of the function is a reference.</p> <p>It works in most scenarios, but the number of combinations of <code>const</code> and <code>volatile</code> increases exponentially with the number of parameters. </p> <p>Whenever it doesn't work -- whether because we have more than one argument or whether overload resolution is rather obscure (for example, when the <code>const</code> version of <code>operator()</code> works, but the non-<code>const</code> version doesn't), the user should use <code>reftype</code> on all arguments before passing them to <code>returns_reference</code>.</p> <p>I <em>think</em> the <code>reftype</code> version might still have a <em>few</em> edge-cases in C++11 (regarding r-value references that are in fact l-lvalues), but it's "good enough" for me for now. At that point, the question of what's actually a "reference" is itself ambiguous anyway. (Although, if we're using C++11, we can just use <code>decltype</code> and forget about all this. The only situation we would still use this under C++11 is if the compiler doesn't support <code>decltype</code> but does support r-value references.)</p> <pre><code>template&lt;bool B&gt; struct static_bool { unsigned char _[B + 1]; static_bool(...) { } operator bool() const { return B; } }; static_bool&lt;false&gt; returns_reference(...) { return false; } template&lt;class T, class F&gt; static_bool&lt;!!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T &amp;(*)(void)&gt;(0) ()))&gt; returns_reference(F, T &amp;) { return NULL; } template&lt;class T, class F&gt; static_bool&lt;!!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T const &amp;(*)(void)&gt;(0) ()))&gt; returns_reference(F, T const &amp;) { return NULL; } template&lt;class T, class F&gt; static_bool&lt;!!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T volatile &amp;(*)(void)&gt;(0) ()))&gt; returns_reference(F, T volatile &amp;) { return NULL; } template&lt;class T, class F&gt; static_bool&lt;!!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T const volatile &amp;(*)(void)&gt;(0) ()))&gt; returns_reference(F, T const volatile &amp;) { return NULL; } template&lt;class T&gt; struct type_wrapper { }; template&lt;class T&gt; type_wrapper&lt;T &amp;&gt; reftype(T &amp;) { return type_wrapper&lt;T &amp;&gt;(); } template&lt;class T&gt; type_wrapper&lt;T const &amp;&gt; reftype(T const &amp;) { return type_wrapper&lt;T const &amp;&gt;(); } template&lt;class T&gt; type_wrapper&lt;T volatile &amp;&gt; reftype(T volatile &amp;) { return type_wrapper&lt;T volatile &amp;&gt;(); } template&lt;class T&gt; type_wrapper&lt;T const volatile &amp;&gt; reftype(T const volatile &amp;) { return type_wrapper&lt;T const volatile &amp;&gt;(); } #if __cplusplus &gt;= 201103L template&lt;class T, class F&gt; static_bool&lt;!!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T &amp;&amp;(*)(void)&gt;(0) ()))&gt; returns_reference(F, T &amp;&amp;) { return NULL; } template&lt;class T, class F&gt; static_bool&lt;!!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T const &amp;&amp;(*)(void)&gt;(0) ()))&gt; returns_reference(F, T const &amp;&amp;) { return NULL; } template&lt;class T, class F&gt; static_bool&lt;!!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T volatile &amp;&amp;(*)(void)&gt;(0) ()))&gt; returns_reference(F, T volatile &amp;&amp;) { return NULL; } template&lt;class T, class F&gt; static_bool&lt;!!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T const volatile &amp;&amp;(*)(void)&gt;(0) ()))&gt; returns_reference(F, T const volatile &amp;&amp;) { return NULL; } template&lt;class T&gt; type_wrapper&lt;T &amp;&amp;&gt; reftype(T &amp;&amp;) { return type_wrapper&lt;T &amp;&amp;&gt;(); } template&lt;class T&gt; type_wrapper&lt;T const &amp;&amp;&gt; reftype(T const &amp;&amp;) { return type_wrapper&lt;T const &amp;&amp;&gt;(); } template&lt;class T&gt; type_wrapper&lt;T volatile &amp;&amp;&gt; reftype(T volatile &amp;&amp;) { return type_wrapper&lt;T volatile &amp;&amp;&gt;(); } template&lt;class T&gt; type_wrapper&lt;T const volatile &amp;&amp;&gt; reftype(T const volatile &amp;&amp;) { return type_wrapper&lt;T const volatile &amp;&amp;&gt;(); } #endif template&lt;class T, class F&gt; static_bool&lt; !!sizeof(&amp;(static_cast&lt;F(*)()&gt;(0) ())(static_cast&lt;T (*)(void)&gt;(0) ())) &gt; returns_reference(type_wrapper&lt;F&gt;, type_wrapper&lt;T&gt; = type_wrapper&lt;T&gt;()) { return NULL; } </code></pre> <p>Test code:</p> <pre><code>struct Test { Test() { } Test(Test &amp;) { } Test(Test const &amp;) { } Test(Test volatile &amp;) { } Test(Test const volatile &amp;) { } Test *operator()(Test *p) const; Test const *operator()(Test const *p) const; Test volatile *operator()(Test volatile *p) const; Test const volatile *operator()(Test const volatile *p) const; Test &amp;operator()(Test &amp;p) const; Test const &amp;operator()(Test const &amp;p) const; Test volatile &amp;operator()(Test volatile &amp;p) const; Test const volatile &amp;operator()(Test const volatile &amp;p) const; #if __cplusplus &gt;= 201103L || defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1700 Test &amp;&amp;operator()(Test &amp;&amp;p) const { return std::move(p); } Test const &amp;&amp;operator()(Test const &amp;&amp;p) const; Test volatile &amp;&amp;operator()(Test volatile &amp;&amp;p) const; Test const volatile &amp;&amp;operator()(Test const volatile &amp;&amp;p) const; #endif }; Test *test1(Test *p); Test const *test2(Test const *p); Test volatile *test3(Test volatile *p); Test const volatile *test4(Test const volatile *p); Test &amp;test5(Test &amp;p); Test const &amp;test6(Test const &amp;p); Test volatile &amp;test7(Test volatile &amp;p); Test const volatile &amp;test8(Test const volatile &amp;p); #if __cplusplus &gt;= 201103L || defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1700 Test &amp;&amp;test9(Test &amp;&amp;p); Test const &amp;&amp;test10(Test const &amp;&amp;p); Test volatile &amp;&amp;test11(Test volatile &amp;&amp;p); Test const volatile &amp;&amp;test12(Test const volatile &amp;&amp;p); #endif int main() { Test t; (void)t; Test const tc; (void)tc; Test volatile tv; (void)tv; Test const volatile tcv; (void)tcv; std::cerr &lt;&lt; (sizeof(returns_reference( t , &amp;t )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( t , &amp;tc )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( t , &amp;tv )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( t , &amp;tcv )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( t , t )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( t , tc )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( t , tv )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( t , tcv )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test1 , &amp;t )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test2 , &amp;tc )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test3 , &amp;tv )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test4 , &amp;tcv )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test5 , t )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test6 , tc )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test7 , tv )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test8 , tcv )) != sizeof(unsigned char)) &lt;&lt; std::endl; #if __cplusplus &gt;= 201103L || defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1700 std::cerr &lt;&lt; (sizeof(returns_reference( test9 , t )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test10 , tc )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test11 , tv )) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference( test12 , tcv )) != sizeof(unsigned char)) &lt;&lt; std::endl; #endif std::cerr &lt;&lt; (sizeof(returns_reference(reftype(t ), reftype(&amp;t ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(t ), reftype(&amp;tc ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(t ), reftype(&amp;tv ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(t ), reftype(&amp;tcv))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(t ), reftype(t ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(t ), reftype(tc ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(t ), reftype(tv ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(t ), reftype(tcv ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test1 ), reftype(&amp;t ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test2 ), reftype(&amp;tc ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test3 ), reftype(&amp;tv ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test4 ), reftype(&amp;tcv))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test5 ), reftype(t ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test6 ), reftype(tc ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test7 ), reftype(tv ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test8 ), reftype(tcv ))) != sizeof(unsigned char)) &lt;&lt; std::endl; #if __cplusplus &gt;= 201103L || defined(_MSC_VER) &amp;&amp; _MSC_VER &gt;= 1700 std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test9 ), reftype(t ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test10), reftype(tc ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test11), reftype(tv ))) != sizeof(unsigned char)) &lt;&lt; std::endl; std::cerr &lt;&lt; (sizeof(returns_reference(reftype(test12), reftype(tcv ))) != sizeof(unsigned char)) &lt;&lt; std::endl; #endif return 0; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
 

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