From: usenet only_tech_talk on
Hello,

Would anyone care to explain the discrepancy between the two compilers
below and perhaps a solution that is viable?

Since thank you only posts are filtered let me say thank you to Daniel
Kr�gler and the others who followed up on his answer for his reply to
my previous post.

namespace toy_crtp{

template< class T >
class A // From an external library, not modifiable
{
public:
void foo() const
{
static_cast<const T&>(*this).foo();
}

void bar() const{ this->foo(); }

};

template<typename T>
class B : protected A< B<T> >
{
typedef B<T> this_;
typedef A<this_> base_;

public:

void bar() const{
base_::bar();
// ...and do something else a bit differently than A
}

};

template<template<typename> class Crtp>
struct C : Crtp< C<Crtp> >{

void foo()const{}

};

}// toy_crtp

int main(){
typedef toy_crtp::C<toy_crtp::A> ca_;
typedef toy_crtp::C<toy_crtp::B> cb_;
ca_ ca; ca.bar();
cb_ cb; cb.bar();

return 0;
}


The above compiles fine under OSX/GCC4.2, but the call cb.bar() for
Ubuntu 9/GCC 4.4.1 causes this:

.../toy_crtp/header1.hpp||In member function �void
toy_crtp::A<T>::foo() const [with T =
toy_crtp::B<toy_crtp::C<toy_crtp::B> >]�:|
.../toy_crtp/header1.hpp|17|instantiated from �void
toy_crtp::A<T>::bar() const [with T =
toy_crtp::B<toy_crtp::C<toy_crtp::B> >]�|
.../toy_crtp/header1.hpp|32|instantiated from �void
toy_crtp::B<T>::bar() const [with T = toy_crtp::C<toy_crtp::B>]�|
/home/erwann/cpp-projects/toy_crtp/main.cpp|13|instantiated from here|
.../toy_crtp/header1.hpp|14|error:
�toy_crtp::A<toy_crtp::B<toy_crtp::C<toy_crtp::B> > >� is an
inaccessible base of �toy_crtp::B<toy_crtp::C<toy_crtp::B> >�|
||=== Build finished: 1 erro



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Johannes Schaub (litb) on
usenet only_tech_talk wrote:

> Hello,
>
> Would anyone care to explain the discrepancy between the two compilers
> below and perhaps a solution that is viable?
>
> Since thank you only posts are filtered let me say thank you to Daniel
> Krügler and the others who followed up on his answer for his reply to
> my previous post.
>
> namespace toy_crtp{
>
> template< class T >
> class A // From an external library, not modifiable
> {
> public:
> void foo() const
> {
> static_cast<const T&>(*this).foo();
> }
>
> void bar() const{ this->foo(); }
>
> };
>
> template<typename T>
> class B : protected A< B<T> >
> {
> typedef B<T> this_;
> typedef A<this_> base_;
>
> public:
>
> void bar() const{
> base_::bar();
> // ...and do something else a bit differently than A
> }
>
> };
>
> template<template<typename> class Crtp>
> struct C : Crtp< C<Crtp> >{
>
> void foo()const{}
>
> };
>
> }// toy_crtp
>
> int main(){
> typedef toy_crtp::C<toy_crtp::A> ca_;
> typedef toy_crtp::C<toy_crtp::B> cb_;
> ca_ ca; ca.bar();
> cb_ cb; cb.bar();
>
> return 0;
> }
>
>
> The above compiles fine under OSX/GCC4.2, but the call cb.bar() for
> Ubuntu 9/GCC 4.4.1 causes this:
>
> ../toy_crtp/header1.hpp||In member function 'void
> toy_crtp::A<T>::foo() const [with T =
> toy_crtp::B<toy_crtp::C<toy_crtp::B> >]':|
> ../toy_crtp/header1.hpp|17|instantiated from 'void
> toy_crtp::A<T>::bar() const [with T =
> toy_crtp::B<toy_crtp::C<toy_crtp::B> >]'|
> ../toy_crtp/header1.hpp|32|instantiated from 'void
> toy_crtp::B<T>::bar() const [with T = toy_crtp::C<toy_crtp::B>]'|
> /home/erwann/cpp-projects/toy_crtp/main.cpp|13|instantiated from here|
> ../toy_crtp/header1.hpp|14|error:
> 'toy_crtp::A<toy_crtp::B<toy_crtp::C<toy_crtp::B> > >' is an
> inaccessible base of 'toy_crtp::B<toy_crtp::C<toy_crtp::B> >'|
> ||=== Build finished: 1 erro
>
>

You are trying to down-cast a protected base class to a derived class. Thus
the error. Notice that even the base class won't be able to access the
inheritance.

You need to use a c-style cast for this instead of a static_cast or need to
change the inheritance to public instead of protected or make the base
class
a friend.

c-style casts disregards accessibility of base classes. To play safe, you
could first check whether "T" is actually a derived class of "A" - because
otherwise a c style cast will be equivalent to a reinterpret_cast, and
possibly could return in undefined behavior. You can check with
boost::is_base_of, which can also cope with private inheritance.

--
[ 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 22 Mrz., 07:02, usenet only_tech_talk <usenet.tech.t...(a)gmail.com>
wrote:
> Would anyone care to explain the discrepancy between the two compilers
> below and perhaps a solution that is viable?
>
> Since thank you only posts are filtered let me say thank you to Daniel
> Kr�gler and the others who followed up on his answer for his reply to
> my previous post.
>
> namespace toy_crtp{
>
> template< class T >
> class A // From an external library, not modifiable
> {
> public:
> void foo() const
> {
> static_cast<const T&>(*this).foo();
> }
>
> void bar() const{ this->foo(); }
>
> };
>
> template<typename T>
> class B : protected A< B<T> >
> {
> typedef B<T> this_;
> typedef A<this_> base_;

You need this line here, see below:

friend void base_::foo() const;

> public:
>
> void bar() const{
> base_::bar();
> // ...and do something else a bit differently than A
> }
>
> };
>
> template<template<typename> class Crtp>
> struct C : Crtp< C<Crtp> >{
>
> void foo()const{}
>
> };
>
> }// toy_crtp
>
> int main(){
> typedef toy_crtp::C<toy_crtp::A> ca_;
> typedef toy_crtp::C<toy_crtp::B> cb_;
> ca_ ca; ca.bar();
> cb_ cb; cb.bar();
> return 0;
> }
>
> The above compiles fine under OSX/GCC4.2, but the call cb.bar() for
> Ubuntu 9/GCC 4.4.1 causes this:

[snip]

A conforming compiler has to reject the code, because
B<T> derives protected from A< B<T> >, which means
that only members of B<T>, derived classes from B<T>,
and friends from B<T> have access to the conversion
of A< B<T> > => B<T> or in general: The conversion
A<T> => T is only possible, if it is accessible within
A<T>. The problem is, that the expression

static_cast<const T&>(*this)

within A<T> performs just this conversion, but if
T derives protected from A<T> (as in this example),
the conversion is ill-formed, if not explicitly granted
via friendship from T to A<T> (in this case I
restricted the friendship to void A<T>::foo() const).

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! ]

From: Michael Doubez on
On 22 mar, 07:02, usenet only_tech_talk <usenet.tech.t...(a)gmail.com>
wrote:
> Hello,
>
> Would anyone care to explain the discrepancy between the two compilers
> below and perhaps a solution that is viable?
>
> Since thank you only posts are filtered let me say thank you to Daniel
> Kr�gler and the others who followed up on his answer for his reply to
> my previous post.
>
> namespace toy_crtp{
>
> template< class T >
> class A // From an external library, not modifiable
> {
> public:
> void foo() const
> {
> static_cast<const T&>(*this).foo();
> }
>
> void bar() const{ this->foo(); }
>
> };
>
> template<typename T>
> class B : protected A< B<T> >
> {
> typedef B<T> this_;
> typedef A<this_> base_;
>
> public:
>
> void bar() const{
> base_::bar();
> // ...and do something else a bit differently than A
> }
>
> };
>
> template<template<typename> class Crtp>
> struct C : Crtp< C<Crtp> >{
>
> void foo()const{}
>
> };
>
> }// toy_crtp
>
> int main(){
> typedef toy_crtp::C<toy_crtp::A> ca_;
> typedef toy_crtp::C<toy_crtp::B> cb_;
> ca_ ca; ca.bar();
> cb_ cb; cb.bar();
>
> return 0;
>
> }
>
> The above compiles fine under OSX/GCC4.2,

It compiles but if you have the same result as mine, you'll have a
segfault.

The template parameter of A is of type B which doesn't possess a foo()
member function. Therefore the call to static_cast<const
T&>(*this).foo(); will call itself and you have a nice recursion (and
eventually a segfault).

To see the error, rename foo() to fooA() in A:
template< class T >
class A // From an external library, not modifiable
{
public:
void fooA() const
{
static_cast<const T&>(*this).foo();
}

void bar() const{ this->fooA(); }

};

And you get the error:

crtpTest.cc: In member function `void toy_crtp::A<T>::fooA() const
[with T = toy_crtp::B<toy_crtp::C<toy_crtp::B> >]':
crtpTest.cc:12: instantiated from `void toy_crtp::A<T>::bar() const
[with T = toy_crtp::B<toy_crtp::C<toy_crtp::B> >]'
crtpTest.cc:25: instantiated from `void toy_crtp::B<T>::bar() const
[with T = toy_crtp::C<toy_crtp::B>]'
crtpTest.cc:44: instantiated from here
crtpTest.cc:9: error: 'const class
toy_crtp::B<toy_crtp::C<toy_crtp::B> >' has no member named 'foo'

> but the call cb.bar() for
> Ubuntu 9/GCC 4.4.1 causes this:
>
[snip]
> /home/erwann/cpp-projects/toy_crtp/main.cpp|13|instantiated from here|
> ../toy_crtp/header1.hpp|14|error:
> �toy_crtp::A<toy_crtp::B<toy_crtp::C<toy_crtp::B> > >� is an
> inaccessible base of �toy_crtp::B<toy_crtp::C<toy_crtp::B> >�|
> ||=== Build finished: 1 erro

I don't know.

--
Michael


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: usenet only_tech_talk on

>
> You need this line here, see below:
>
> friend void base_::foo() const;

Actually, GCC 4.4 in Ubuntu wants this

friend class A<this_>;

to compile, but the bad news is that

>
> > cb_ cb; cb.bar();

causes a segmentation fault at runtime.

Thanks for the previous replies.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]