Topic: Compile-time inheritance checking


Author: comeau@panix.com (Greg Comeau)
Date: 2000/04/02
Raw View
In article <8bu36j$2m8$1@nnrp1.deja.com> Arint    <jamarijr@hotmail.com> writes:
>
>> >> typedef char (&no)[1];
>> >> typedef char (&yes)[2];
>
>...trouble also with those 2 lines up there.  But, I will figure it out
>sooner or later I guess.

The deal is that you cannot directly return an array from a function.
That means you need to "wrap" it in something.  Often in C
the wrapper is a struct, but in C++ we can have references
to arrays, and that's what the above is about.

- Greg
--
Comeau Computing, Producers of Comeau C/C++ 4.2.42 (4.2.43 BETA starting)
Try Comeau C++ online at http://www.comeaucomputing.com/tryitout
Email: comeau@comeaucomputing.com / WEB: http://www.comeaucomputing.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Arint " <shouldbe@message.com>
Date: 2000/03/29
Raw View
Could you explain what this code does a little more?
>
> template <class Base, class Candidate>
> class Checker
> {
>     typedef char (&no)[1];
>     typedef char (&yes)[2];
>
>     yes Test(Base*);
>     no Test(...);
>
> public:
>     enum { CandidateIsDerivedFromBase =
>         sizeof(Test((Candidate*)0)) == sizeof(yes) };
> };
>



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Herb Sutter <hsutter@peerdirect.com>
Date: 2000/03/30
Raw View
On Wed, 29 Mar 2000 00:56:24 CST, "Arint   " <shouldbe@message.com> wrote:
>Could you explain what this code does a little more?
>>
>> template <class Base, class Candidate>
>> class Checker
>> {
>>     typedef char (&no)[1];
>>     typedef char (&yes)[2];
>>
>>     yes Test(Base*);
>>     no Test(...);
>>
>> public:
>>     enum { CandidateIsDerivedFromBase =
>>         sizeof(Test((Candidate*)0)) == sizeof(yes) };
>> };

Cute, isn't it?

First, remember that both sizeof() and enum values are evaluated at
compile-time; i.e., no code is actually called, they operate on types
and/or compile-time values only.

Next, consider the expression "Test((Candidate*)0)". It's never actually
executed; it simply names a Candidate* and "calls" Test() with it so as
to invoke overload resolution, which will then choose Test(Base*) as the
best match iff a Candidate* can be converted to a Base*, or Test(...)
otherwise. This means that if Candidate* can be converted to Base*, the
type of the expression "Test((Candidate*)0)" is yes, else the type of
the expression is no.

Next, consider that yes and no have different sizes, and so sizeof() can
distinguish between them. In fact, the value of
CandidateIsDerivedFromBase, which is also evaluated at compile time, is
then set to true iff Candidate is derived from Base (publicly,
unambiguously, and possibly indirectly).

You don't even need to define the Test() functions because they're there
for the type signatures only; they're never actually called.

Using the above, you can enforce template constraints at compile time. I
remember reading a longer and more general Constraints technique in an
article somewhere. The reference escapes me now.

Herb

---
Herb Sutter (mailto:hsutter@peerdirect.com)

CTO, PeerDirect Inc. (http://www.peerdirect.com)
Chair, ANSI H2 Ad-Hoc for SQL Part 12: SQL/Replication
  (Replication working group, ANSI SQL committee)
Editor-in-Chief, C++ Report (http://www.creport.com)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/03/30
Raw View
Herb Sutter <hsutter@peerdirect.com> wrote in message
news:j984esgock1upca0g4o5lo888on7a2eu4k@4ax.com...
> On Wed, 29 Mar 2000 00:56:24 CST, "Arint   " <shouldbe@message.com> wrote:
> >Could you explain what this code does a little more?
> >>
> >> template <class Base, class Candidate>
> >> class Checker
> >> {
> >>     typedef char (&no)[1];
> >>     typedef char (&yes)[2];
> >>
> >>     yes Test(Base*);
> >>     no Test(...);
> >>
> >> public:
> >>     enum { CandidateIsDerivedFromBase =
> >>         sizeof(Test((Candidate*)0)) == sizeof(yes) };
> >> };

> You don't even need to define the Test() functions because they're there
> for the type signatures only; they're never actually called.

Which reminds me that I forgot to make the two Test functions above static.


Andrei


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Arint <jamarijr@hotmail.com>
Date: 2000/03/31
Raw View
> >> typedef char (&no)[1];
> >> typedef char (&yes)[2];

Thanks Herb, and dangit if I could spare the bucks I would buy your Mag
(C++ Report if you forgot about one of your jobs), I tried to get them
to order it at work, but they are tripping anywho.  I was having
trouble also with those 2 lines up there.  But, I will figure it out
sooner or later I guess.


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/03/31
Raw View
Try this:

typedef char no;
class yes { char m_[2]; };

The only requrement for 'yes' and 'no' is to have different sizes. I'd be
glads if you let us know how it worked. And don't forget to prepend 'static'
to the two declarations of Test.


Andrei

Arint    <jamarijr@hotmail.com> wrote in message
news:8bu36j$2m8$1@nnrp1.deja.com...
>
> > >> typedef char (&no)[1];
> > >> typedef char (&yes)[2];
>
> Thanks Herb, and dangit if I could spare the bucks I would buy your Mag
> (C++ Report if you forgot about one of your jobs), I tried to get them
> to order it at work, but they are tripping anywho.  I was having
> trouble also with those 2 lines up there.  But, I will figure it out
> sooner or later I guess.
>
>
> Sent via Deja.com http://www.deja.com/
> Before you buy.
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]
>


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Jacques Lolieux <j_lolieux@effix.fr>
Date: 2000/03/24
Raw View
Given the following code:


template <class T> struct outer {
    struct inner {
        virtual ~inner();
        T *foo();
        ...
    };
    enum { size = sizeof(inner) };
};
const int i = outer<int>::size;


In order to compute sizeof(inner) does the compiler have to evaluate (or
whatever the word) the whole class even if it is defined inside a
template?
In other words, does the standard requires the compiler to evaluate the
whole inner class, or does it allow the compiler to be leazy and just
check for member data if no member functions are ever used?
I could not find anything in the standard about this case.

The reason I need to know this is that I am writing a library which
relies on constraint genericity, and I am wondering if the code that
checks inheritance relationship between two classes is portable or if I
am relying on some compiler specific features.

The library goes something like this:

template <class T, class U> void foo(...) {
    // compilation error if T is not a base class of U
    inheritance_check(T, U);

    ...
}

The inheritance_check() macro is defined as:

template <class T, class U> struct inheritance_checker {
    struct base {
        virtual T *foo(); // covariance to check inheritance
    };
    struct derived: base {
        virtual U *foo(); // covariance to check inheritance
    };
    enum {
        dummy = sizeof(derived) // force an evaluation
    };
};
#define inheritance_check(A, B) \
    typedef int check[inheritance_checker<A,B>::dummy]


Any idea?


Jacques Lolieux

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/03/25
Raw View
Jacques Lolieux <j_lolieux@effix.fr> wrote in message
news:38DA244F.EB3328DA@effix.fr...
[snip]

As far as I understand, your implementation is incorrect.

You may want to look up deja.com for a post called "base-driven template
specialization", written by myself. In turn, that post refers to another
post that shows how to check for inheritance at compile time.

I'll try to quickly reproduce the code from memory:

template <class Base, class Candidate>
class Checker
{
    typedef char (&no)[1];
    typedef char (&yes)[2];

    yes Test(Base*);
    no Test(...);

public:
    enum { CandidateIsDerivedFromBase =
        sizeof(Test((Candidate*)0)) == sizeof(yes) };
};

The code relies on overloading rules.

The original code was more general allowing you to detect implicit
conversion between arbitrary types at compile time.

Anyways, your inheritance_checker can be written without the scaffolding
above like this:

#define inheritance_check(T, U) { T* pDummy = (U*)0; }

or something to that effect.


Andrei


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Ewgenij Gawrilow <gawrilow@math.tu-berlin.de>
Date: 2000/03/25
Raw View
In article <sdmb09uulul73@news.supernews.com>,
"Andrei Alexandrescu" <andrewalex@hotmail.com> wrote:
>
> You may want to look up deja.com for a post called "base-driven
> template specialization", written by myself. In turn, that post refers
> to specialization", written by myself. In turn, that post refers to
> another post that shows how to check for inheritance at compile time.
>
> I'll try to quickly reproduce the code from memory
I was so admired having seen it, that immediately tested it with gcc
2.95.2. Unfortunately, it didn't compile. But slightly modified, it
works:
template <class Base, class Candidate>
class Checker_helper
{
typedef char (&no)[1];
typedef char (&yes)[2];
public:
static yes Test(Base*);
static no Test(...);
};
template <class Base, class Candidate>
class Checker {
public:
enum { CandidateIsDerivedFromBase =
sizeof(Checker_helper<Base,Candidate>::Test((Candidate*)0)) ==
sizeof(Checker_helper<Base,Candidate>::yes) };
};
It is great!!!
With best regards,
Ewgenij Gawrilow
Dept. of Mathematics
Technical University Berlin, Germany


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]