fork(1) download
  1. #include<iostream>
  2. #include<string>
  3. #include<type_traits>
  4. using std::string;
  5. using std::cerr;
  6. using std::endl;
  7.  
  8. // base trait class stores data we want to access & modify in a uniform manner at runtime
  9. struct TraitBase{
  10. string _name, _label;
  11. };
  12. // template derived class stores data that are accessed at compile-time
  13. template<int _flags>
  14. struct Trait: public TraitBase{
  15. // saves compile-time flags for easy access
  16. enum{flags=_flags};
  17. // named parameter idiom; must be defined here (not in TraitBase) so that ref to ourselves is returned
  18. // in that way, chained expression retains template parameters
  19. Trait& name(const string& s){ _name=s; return *this; }
  20. Trait& label(const string& s){ _label=s; return *this; }
  21. };
  22.  
  23. struct Foo{
  24. #define aTrait Trait<23>().name("a").label("[original label]")
  25. int a;
  26. static decltype(aTrait)& makeTrait_a(){
  27. // remove reference in case named parameters are used in aTrait
  28. static std::remove_reference<decltype(aTrait)>::type _a=aTrait;
  29. return _a;
  30. }
  31. // we need std::remove_reference for decltype (otherwise error with gcc 4.5)
  32. //
  33. // this typedef also works around limited support for decltype in gcc-4.5;
  34. // e.g. std::remove_reference<decltype(Foo::makeTrait_a())>::type::flags would fail
  35. typedef std::remove_reference<decltype(Foo::makeTrait_a())>::type TraitType_a;
  36. };
  37.  
  38. template<int val> void printFlags(){ cerr<<"[compile-time flags "<<val<<"]\n"; }
  39.  
  40. int main(void){
  41. // show compile-time resolution
  42. printFlags<Foo::TraitType_a::flags>();
  43.  
  44. // show that static initialization works
  45. cerr<<Foo::makeTrait_a()._name<<": "<<Foo::makeTrait_a()._label<<endl;
  46.  
  47. // show that reference to the single object is passed around properly
  48. Foo::makeTrait_a().label("[changed label]");
  49. cerr<<Foo::makeTrait_a()._name<<": "<<Foo::makeTrait_a()._label<<endl;
  50. }
Success #stdin #stdout 0s 2960KB
stdin
Standard input is empty
stdout
Standard output is empty