Prev: How to call templated static function from another template function?
Next: Is it possible to use object functions as arguments to the inner_product algorithm?
From: usenet only_tech_talk on 21 Mar 2010 15:02 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 21 Mar 2010 21:35 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 21 Mar 2010 21:35 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 22 Mar 2010 02:59 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 22 Mar 2010 03:03
> > 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! ] |