fork(2) download
  1. #include <type_traits>
  2. #include <iostream>
  3.  
  4. // interface class
  5. class A
  6. {
  7. public:
  8. virtual void foo() = 0;
  9. virtual ~A() {}
  10. };
  11.  
  12. namespace detail
  13. {
  14. // an helper for traits
  15. template <typename T>
  16. decltype(T{}, std::cout << T{}, std::true_type{})
  17. helper_has_default_constructor_and_foo(int);
  18.  
  19. template <typename T>
  20. std::false_type helper_has_default_constructor_and_foo(...);
  21.  
  22. // the traits
  23. template <typename T>
  24. using has_default_constructor_and_foo = decltype(helper_has_default_constructor_and_foo<T>(0));
  25.  
  26. // genaral case (so when traits is false)
  27. template <typename T, typename = has_default_constructor_and_foo<T>>
  28. struct C : public A {};
  29.  
  30. // specialization when traits is true
  31. template <typename T>
  32. struct C<T, std::true_type> : public A
  33. {
  34. void foo() override { std::cout << T{}; }
  35. };
  36.  
  37. }
  38.  
  39. template <typename T>
  40. class B : public detail::C<T>
  41. {
  42. };
  43.  
  44. // concrete classes
  45. // will work on it's own
  46. typedef B<std::string> C;
  47.  
  48. class D : public B<void>
  49. {
  50. public:
  51. // B<void>::foo won't instantiate on it's own
  52. // so we provide help here
  53. void foo() override {}
  54. };
  55.  
  56. int main()
  57. {
  58. //B<void> b; // error as expected
  59. B<int> b;
  60. C c;
  61. D d;
  62.  
  63. b.foo(); // 0
  64. c.foo(); // empty string
  65. d.foo(); // nothing
  66. }
  67.  
Success #stdin #stdout 0s 3140KB
stdin
Standard input is empty
stdout
Standard output is empty