fork(1) download
  1. #include <iostream>
  2.  
  3. template < typename T >
  4. struct has_foo
  5. {
  6. typedef char yes;
  7. typedef char no[2];
  8.  
  9. // Type that has a member with the name that will be checked.
  10. struct fallback { int foo; };
  11.  
  12. // Type that will inherit from both T and mixin to guarantee that mixed_type
  13. // has the desired member. If T::foo exists, then &mixed_type::foo will be
  14. // ambiguous. Otherwise, if T::foo does not exists, then &mixed_type::foo
  15. // will successfully resolve to fallback::foo.
  16. struct mixed_type: T, fallback {};
  17.  
  18. template < typename U, U > struct type_check {};
  19.  
  20. // If substituation does not fail, then &U::foo is not ambiguous, indicating
  21. // that mixed_type only has one member named foo (i.e. fallback::foo).
  22. template < typename U > static no& test( type_check< int (fallback::*),
  23. &U::foo >* = 0 );
  24.  
  25. // Substituation failed, so &U::foo is ambiguous, indicating that mixed_type
  26. // has multiple members named foo. Thus, T::foo exists.
  27. template < typename U > static yes& test( ... );
  28.  
  29. static const bool value = sizeof( yes ) ==
  30. sizeof( test< mixed_type >( NULL ) );
  31. };
  32.  
  33. namespace detail {
  34. class yes {};
  35. class no{ yes m[2]; };
  36.  
  37. // sizeof will be used to determine what function is selected given an
  38. // expression. An overloaded comma operator will be used to branch based
  39. // on types at compile-time.
  40. // With ( helper, anything-other-than-no, yes ) return yes.
  41. // With ( helper, no, yes ) return no.
  42. struct helper {};
  43.  
  44. // Return helper.
  45. template < typename T > helper operator,( helper, const T& );
  46.  
  47. // Overloads.
  48. yes operator,( helper, yes ); // For ( helper, yes ) return yes.
  49. no operator,( helper, no ); // For ( helper, no ) return no.
  50. no operator,( no, yes ); // For ( no, yes ) return no.
  51. } // namespace detail
  52.  
  53. template < typename T >
  54. struct can_call_foo
  55. {
  56. struct fallback { ::detail::no foo( ... ) const; };
  57.  
  58. // Type that will inherit from T and fallback, this guarantees
  59. // that mixed_type has a foo method.
  60. struct mixed_type: T, fallback
  61. {
  62. using T::foo;
  63. using fallback::foo;
  64. };
  65.  
  66. // U has a foo member.
  67. template < typename U, bool = has_foo< U >::value >
  68. struct impl
  69. {
  70. // Create the type sequence.
  71. // - Start with helper to guarantee the custom comma operator is used.
  72. // - This is evaluationg the expression, not executing, so cast null
  73. // to a mixed_type pointer, then invoke foo. If T::foo is selected,
  74. // then the comma operator returns helper. Otherwise, fooback::foo
  75. // is selected, and the comma operator returns no.
  76. // - Either helper or no was returned from the first comma operator
  77. // evaluation. If ( helper, yes ) remains, then yes will be returned.
  78. // Otherwise, ( no, yes ) remains; thus no will be returned.
  79. static const bool value = sizeof( ::detail::yes ) ==
  80. sizeof( ::detail::helper(),
  81. ((mixed_type*)0)->foo(),
  82. ::detail::yes() );
  83. };
  84.  
  85. // U does not have a 'foo' member.
  86. template < typename U >
  87. struct impl< U, false >
  88. {
  89. static const bool value = false;
  90. };
  91.  
  92. static const bool value = impl< T >::value;
  93. };
  94.  
  95. // Types containing a foo member function.
  96. struct B { void foo(); };
  97. struct D1: B { bool foo(); }; // hide B::foo
  98. struct D2: B { using B::foo; }; // no-op, as no hiding occured.
  99. struct D3: B { };
  100.  
  101. // Type that do not have a member foo function.
  102. struct F {};
  103.  
  104. // Type that has foo but it is not callable via T::foo().
  105. struct G { int foo; };
  106. struct G1 { bool foo( int ); };
  107.  
  108. int main ()
  109. {
  110. std::cout << "B: " << has_foo< B >::value << " - "
  111. << can_call_foo< B >::value << "\n"
  112. << "D1: " << has_foo< D1 >::value << " - "
  113. << can_call_foo< D1 >::value << "\n"
  114. << "D2: " << has_foo< D2 >::value << " - "
  115. << can_call_foo< D2 >::value << "\n"
  116. << "D3: " << has_foo< D3 >::value << " - "
  117. << can_call_foo< D3 >::value << "\n"
  118. << "F: " << has_foo< F >::value << " - "
  119. << can_call_foo< F >::value << "\n"
  120. << "G: " << has_foo< G >::value << " - "
  121. << can_call_foo< G >::value << "\n"
  122. << "G1: " << has_foo< G1 >::value << " - "
  123. << can_call_foo< G1 >::value << "\n"
  124. << std::endl;
  125. return 0;
  126. }
Success #stdin #stdout 0.02s 2680KB
stdin
Standard input is empty
stdout
B:  1 - 1
D1: 1 - 1
D2: 1 - 1
D3: 1 - 1
F:  0 - 0
G:  1 - 0
G1: 1 - 0