From: Frank Bergemann on
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
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
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
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
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! ]