Prev: Why is the return type of count_if() "signed" rather than "unsigned"?
Next: Why is the return type of count_if() "signed" rather than "unsigned"?
From: Frank Bergemann on 22 Jun 2010 09:11 Hello, i tried this one here to get information, if a class X inherits from a Feature class: ------------------------- snip ---------------------------------------- #include <iostream> using namespace std; struct NO { static const int VALUE = 0; }; struct YES { static const int VALUE = 1; }; namespace Feature { template <class Base> class Class { public: Class() { }; ~Class() { }; }; // template for indicator of Feature - default NO template <class QueryBase> class Indicator { public: typedef NO VALUE; }; // explicit instantiation of indicator of Feature<Base> - YES template<class QueryBase> class Indicator <Class<QueryBase> > { public: typedef YES VALUE; }; }; // namespace Feature class TestA { public: TestA() { }; ~TestA() { }; }; class TestB : public Feature::Class<TestB> { public: TestB() { }; ~TestB() { }; }; int main(int, char**) { TestB b; cout << "Indicator<TestA> = " << Feature::Indicator<TestA>::VALUE::VALUE << endl; cout << "Indicator<TestB> = " << Feature::Indicator<TestB>::VALUE::VALUE << endl; cout << "Indicator<Feature<TestA> > = " << Feature::Indicator<Feature::Class<TestA> >::VALUE::VALUE << endl; return 0; } ------------------------- snap ---------------------------------------- But it doesn't work: frank(a)frank-desktop-2:~$ g++ -o test test.cc frank(a)frank-desktop-2:~$ ./test Indicator<TestA> = 0 Indicator<TestB> = 0 Indicator<Feature<TestA> > = 1 Is there a way to get this information also for Feature::Indicator<TestB> ? - thanks! regards, Frank -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: CornedBee on 22 Jun 2010 23:09 On Jun 23, 2:11 am, Frank Bergemann <FBergem...(a)web.de> wrote: > Hello, > > i tried this one here to get information, if a class X inherits from a Feature class: Try the is_base_of type trait, available in Boost, TR1 or C++0x std. Sebastian -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Frank Bergemann on 22 Jun 2010 23:03 this one works now: (i've stolen the sizeof-trick from "C++ Template Metaprogramming") ----------------------- snip ---------------------- #include <iostream> #include <boost/mpl/bool.hpp> using namespace std; namespace Feature { typedef char yes; // sizeof(yes) == 1 typedef char (&no)[2]; // sizeof(no) == 2 template <class Base> class Class { public: struct INDICATOR { INDICATOR(int value) {}; }; Class() { }; ~Class() { }; }; template <class T> struct isClass { template <class U> static yes tester(typename U::INDICATOR value); template <class U> static no tester(...); static bool const value = sizeof(isClass::tester<T>(0)) == sizeof(yes); typedef boost::mpl::bool_<value> type; }; }; // namespace Feature class TestA { public: TestA() { }; ~TestA() { }; }; class TestB : public Feature::Class<TestB> { public: TestB() { }; ~TestB() { }; }; int main(int, char**) { cout << "Indicator<int> = " << Feature::isClass<int>::value << endl; cout << "Indicator<TestA> = " << Feature::isClass<TestA>::value << endl; cout << "Indicator<TestB> = " << Feature::isClass<TestB>::value << endl; cout << "Indicator<Feature<TestA> > = " << Feature::isClass<Feature::Class<TestA> >::value<< endl; return 0; } ----------------------- snap ---------------------- frank(a)frank-desktop:~$ g++ -o test test.cc frank(a)frank-desktop:~$ ./test Indicator<int> = 0 Indicator<TestA> = 0 Indicator<TestB> = 1 Indicator<Feature<TestA> > = 1 But there is a little flaw for potential collisions of nested struct INDICATOR. Someone could have such in a foreign class as well. Is there a way to make it safer? regards, Frank -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Frank Bergemann on 22 Jun 2010 23:08 another version to avoid collisions between different classes, that use this mechanism: ----------------------- snip -------------------------------------- #include <iostream> #include <boost/mpl/bool.hpp> using namespace std; namespace FeatureX { typedef char yes; // sizeof(yes) == 1 typedef char (&no)[2]; // sizeof(no) == 2 template <class Base> class Test { private: struct FeatureXTest { FeatureXTest(int value) {}; }; }; template <class T> class isClass { public: template <class U> static yes tester(typename U::FeatureXTest value); template <class U> static no tester(...); static bool const value = sizeof(isClass::tester<T>(0)) == sizeof(yes); typedef boost::mpl::bool_<value> type; }; template <class Base> class Class : public Test<Base> { friend class isClass<Base>; public: Class() { }; ~Class() { }; }; }; // namespace FeatureX namespace FeatureY { typedef char yes; // sizeof(yes) == 1 typedef char (&no)[2]; // sizeof(no) == 2 template <class Base> class Test { private: struct FeatureYTest { FeatureYTest(int value) {}; }; }; template <class T> class isClass { public: template <class U> static yes tester(typename U::FeatureYTest value); template <class U> static no tester(...); static bool const value = sizeof(isClass::tester<T>(0)) == sizeof(yes); typedef boost::mpl::bool_<value> type; }; template <class Base> class Class : public Test<Base> { friend class isClass<Base>; public: Class() { }; ~Class() { }; }; }; // namespace FeatureY class TestA { public: TestA() { }; ~TestA() { }; }; class TestB : public FeatureX::Class<TestB> { public: TestB() { }; ~TestB() { }; }; class TestC : public FeatureY::Class<TestC> { public: TestC() { }; ~TestC() { }; }; int main(int, char**) { cout << "FeatureX::isClass<int> = " << FeatureX::isClass<int>::value << endl; cout << "FeatureX::isClass<TestA> = " << FeatureX::isClass<TestA>::value << endl; cout << "FeatureX::isClass<TestB> = " << FeatureX::isClass<TestB>::value << endl; cout << "FeatureX::isClass<Feature<TestA> > = " << FeatureX::isClass<FeatureX::Class<TestA> >::value<< endl; cout << "FeatureY::isClass<TestC> = " << FeatureY::isClass<TestC>::value << endl; // cross-over checks cout << "FeatureX::isClass<TestC> = " << FeatureX::isClass<TestC>::value << endl; cout << "FeatureY::isClass<TestB> = " << FeatureY::isClass<TestB>::value << endl; return 0; } ----------------------- snap -------------------------------------- frank(a)frank-desktop:~$ g++ -o test test.cc frank(a)frank-desktop:~$ ./test FeatureX::isClass<int> = 0 FeatureX::isClass<TestA> = 0 FeatureX::isClass<TestB> = 1 FeatureX::isClass<Feature<TestA> > = 1 FeatureY::isClass<TestC> = 1 FeatureX::isClass<TestC> = 0 FeatureY::isClass<TestB> = 0 But still don't like the required naming conventions for struct FeatureXTest { ... } respectively struct FeatureYTest { ... } Is there a way to get rid of this? - thanks! regards, Frank -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Daniel Krügler on 22 Jun 2010 23:07
On 23 Jun., 02:11, Frank Bergemann <FBergem...(a)web.de> wrote: [..] > i tried this one here to get information, if a class X inherits from a Feature class: > ------------------------- snip ---------------------------------------- > > #include <iostream> > using namespace std; > > struct NO > { > static const int VALUE = 0; > }; > > struct YES > { > static const int VALUE = 1; > }; > > namespace Feature > { > > template <class Base> I assume, "Base" should better be renamed to "Derived", because you are supposed to provider the sub-class type, right? > class Class > { > public: > Class() { }; > ~Class() { }; > }; > > // template for indicator of Feature - default NO > template <class QueryBase> > class Indicator > { > public: > typedef NO VALUE; > }; > > // explicit instantiation of indicator of Feature<Base> - YES > template<class QueryBase> > class Indicator <Class<QueryBase> > > { > public: > typedef YES VALUE; > }; > > }; // namespace Feature > > class TestA > { > public: > TestA() { }; > ~TestA() { }; > }; > > class TestB : public Feature::Class<TestB> > { > public: > TestB() { }; > ~TestB() { }; > }; OK, TestB *derives* from Feature::Class<TestB>, but that doesn't mean that a template type deduction will evaluate that TestB is the same as Feature::Class<TestB> > int main(int, char**) > { > > TestB b; > cout << "Indicator<TestA> = " << Feature::Indicator<TestA>::VALUE::VALUE << endl; > cout << "Indicator<TestB> = " << Feature::Indicator<TestB>::VALUE::VALUE << endl; > cout << "Indicator<Feature<TestA> > = " << Feature::Indicator<Feature::Class<TestA> >::VALUE::VALUE << endl; > return 0; > } > > ------------------------- snap ---------------------------------------- > > But it doesn't work: > > frank(a)frank-desktop-2:~$ g++ -o test test.cc > frank(a)frank-desktop-2:~$ ./test > Indicator<TestA> = 0 > Indicator<TestB> = 0 > Indicator<Feature<TestA> > = 1 > > Is there a way to get this information also for Feature::Indicator<TestB> ? You may want to use boost::is_base_of<Feature::Class<TestB>, TestB> or - if you use a compiler with C++0x feastures - std::is_base_of<Feature::Class<TestB>, TestB> to check whether TestB is a super-class of Feature::Class<TestB>. The is_base_of traits also works for same types. Given this trait class you could define a single primary template for Indicator, e.g. template <class Derived> struct Indicator { typedef typename boost::mpl::if_c<boost::is_base_of<Class<Derived>, Derived>::value, YES, NO>::type VALUE; }; or template <class Derived> struct Indicator { typedef typename std::conditional<std::is_base_of<Class<Derived>, Derived>::value, YES, NO>::type VALUE; }; HTH & Greetings from Bremen, Daniel Kr�gler -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |