Prev: Templates in application level code (was: Re: Any hopes for export ?)
Next: Why cannot I get initializer_list like objects without using them? Please, why wouldn't the code (1) below work with c++0x?
From: Lorenzo Caminiti on 29 Jul 2010 04:14 On Jul 29, 11:06 am, Goran Pusic <gor...(a)cse-semaphore.com> wrote: > (You could have shown definition of BLOCK_INVARIANT) I have not yet implemented `BLOCK_INVARIANT()` so I do not have its #definition. Plus that would be too much code for this email thread... If you are curious, I will implement the macro using preprocessor/ template metaprogramming (Boost.Preprocessor/Boost.MPL) in ways similar to what I am doing for other macros in this library: http://dbcpp.svn.sourceforge.net/viewvc/dbcpp/trunk/src/contract/aux_/prepro cessor/ .. For example, look at `CONTRACT_AUX_PP_SIGN_PARSE_FUNCTION()` and `CONTRACT_AUX_PP_KEYWORD_IS_THIS()`. > That said, if const-correctness is your goal, then you still don't > need additional class. A const_cast (no blind C casts please, we're in > C++ ;-) ) could do, couldn't it? > > What if you simply do: > > #define BLOCK_INVARIANT(object_type, check, param_type, param) \ > { if (!const_cast<const object_type*>(this)->check((const param_type&) > (param))) throw -1;} > > and then, in f(): > > BLOCK_INVARIANT(c, eq, int, x). This works in the specific example I have listed but the `BLOCK_INVARIANT()` macro needs to be more generic than that. The macro needs to handle *any* code expression that can be evaluated to a boolean within the context where the macro is used (i.e., the function `f()` in this example). For example the same `BLOCK_INVARIANT()` macro handles all these different invariant assertions and checks them in constant-correct context: class c { public: c(int x): x_(x) {} bool eq(int x) const { return x_ == x; }; int delta() const { return 10; } void f(int x) { BLOCK_INVARIANT( (const (c*)(this) (int)(x) (this_->eq(x) == false)) ) int y = x; BLOCK_INVARIANT( (const (int)(y) (int)(x) (y == x)) ) int z = x + y + this->delta(); BLOCK_INVARIANT( (const (int)(z) (int)(x) (int)(y) (c*) (this) (z == x + y + this_->delta()) ) } private: int x_; }; > By the way, that throw -1 stands out like a sore thumb. How's that That's just for the example, don't worry about it -- it'll never make it into real code :) -- Lorenzo -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Lorenzo Caminiti on 29 Jul 2010 07:10 On Jul 29, 11:05 am, Anthony Williams <anthony....(a)gmail.com> wrote: > Lorenzo Caminiti <lorcamin...(a)gmail.com> writes: >> However, ideally the code expression passed to `BLOCK_INVARIANT()` >> will looks the exactly the same as the code programmed within `f()`. >> Therefore, `this_->eq(x)` will ideally be `this->eq(x)`. Is there a >> way I can do this without inheriting `block_inv` from `c`? And that is >> what I need. > > No, you cannot do that. "this" refers to an instance of the current > class. Inside member functions of a local class, "this" refers to an > instance of that local class. > > You can do it with a nasty (i.e. strictly undefined behaviour, but works > in practice) hack though: if your local class has no data members and no > virtual functions then you can derive the local class from the outer > class and cast your "this" pointer to be an instance of the local class: > > #include <iostream> > class X > { > private: > void g() const > { > std::cout<<"g(), this="<<this<<std::endl; > } > public: > void f() > { > std::cout<<"f(), this="<<this<<std::endl; > struct local:X > { > void foo() const > { > this->g(); > } > }; > > local const* p=static_cast<local const*>(const_cast<X > const*>(this)); > p->foo(); > } > > }; > > int main() > { > X x; > x.f(); > > } Yes, this actually does what I need -- thanks a lot!! However, I cannot use it if its behavior is undefined as per the C++ standard... I can only use legal standardized C++... *** Can you please explain more about why the behavior of this code is undefined? *** I reworked my previous example using your solution and it compiles just fine on MSVC: class c { public: c(int x): x_(x) {} bool eq(int x) const { return x_ == x; }; void f(int x) { // This macro: // BLOCK_INVARIANT( (const (c*)(this) (int)(x) (eq(x) == false)) ) // will expand to: struct block_inv: remove_pointer<c*>::type { void check(int const& x) const { if(!( eq(x) == false )) { // Doesn't even have to use `this`, like if it were in `f()`!! std::cerr << "Block invariant broken" << std::endl; throw int(-1); } std::clog << "Block invaraint passed" << std::endl; } }; static_cast<block_inv const&>( const_cast<remove_pointer<c*>::type const&>(*this)).check(x); } private: int x_; }; The code within the macro and therefore within the local class member function `check()` doesn't even have to use `this`. It simply reads `eq(x)` as it would if it were written directly within `f()` -- that is exactly what I needed! -- Lorenzo -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Anthony Williams on 30 Jul 2010 00:18 Lorenzo Caminiti <lorcaminiti(a)gmail.com> writes: > On Jul 29, 11:05 am, Anthony Williams <anthony....(a)gmail.com> wrote: >> You can do it with a nasty (i.e. strictly undefined behaviour, but works >> in practice) hack though: if your local class has no data members and no >> virtual functions then you can derive the local class from the outer >> class and cast your "this" pointer to be an instance of the local class: >> local const* p=static_cast<local const*>(const_cast<X >> const*>(this)); >> p->foo(); > Yes, this actually does what I need -- thanks a lot!! However, I > cannot use it if its behavior is undefined as per the C++ standard... > I can only use legal standardized C++... > > *** Can you please explain more about why the behavior of this code is > undefined? *** It is undefined behaviour to access an object through a pointer or reference to a type other then the dynamic type of the object or a base class of the dynamic type of the object. Since local is a *derived* type of the object (which is type X) this is undefined behaviour. It works in practice on all compilers I'm aware of though, provided local has no data members or virtual functions and only the one base class. Anthony -- Author of C++ Concurrency in Action http://www.stdthread.co.uk/book/ just::thread C++0x thread library http://www.stdthread.co.uk Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976 [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: terminator on 2 Aug 2010 03:43 On Jul 30, 2:10 am, Lorenzo Caminiti <lorcamin...(a)gmail.com> wrote: > On Jul 29, 11:05 am, Anthony Williams <anthony....(a)gmail.com> wrote: > > You can do it with a nasty (i.e. strictly undefined behaviour, but works > > in practice) hack though: if your local class has no data members and no > > virtual functions then you can derive the local class from the outer > > class and cast your "this" pointer to be an instance of the local class: > > > #include <iostream> > > class X > > { > > private: > > void g() const > > { > > std::cout<<"g(), this="<<this<<std::endl; > > } > > public: > > void f() > > { > > std::cout<<"f(), this="<<this<<std::endl; > > struct local:X > > { > > void foo() const > > { > > this->g(); > > } > > }; > > > local const* p=static_cast<local const*>(const_cast<X > > const*>(this)); > > p->foo(); > > } > > > }; > > > int main() > > { > > X x; > > x.f(); > > > } > > Yes, this actually does what I need -- thanks a lot!! However, I > cannot use it if its behavior is undefined as per the C++ standard... > I can only use legal standardized C++... > > *** Can you please explain more about why the behavior of this code is > undefined? *** > > - Show quoted text - UB=Undefined behavior.That means there is no standard about that behavior and every compiler is free to handle it in its own way.The above example of UB is mostly due to probable memory overhead of derivation which migth be used for RTTI and is platform dependent.UB might show up as a program crash(sudden death) or a runtime/OS error,... regards, FM. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Lorenzo Caminiti on 3 Aug 2010 07:20
On Jul 30, 11:18 am, Anthony Williams <anthony....(a)gmail.com> wrote: > Lorenzo Caminiti <lorcamin...(a)gmail.com> writes: > > > *** Can you please explain more about why the behavior of this code is > > undefined? *** > > It is undefined behaviour to access an object through a pointer or > reference to a type other then the dynamic type of the object or a base > class of the dynamic type of the object. Since local is a *derived* type > of the object (which is type X) this is undefined behaviour. It works in > practice on all compilers I'm aware of though, provided local has no > data members or virtual functions and only the one base class. Thank you all for the suggestions and clarifications. I think this fully answers my original question unless there is a way to program this without relying on undefined behavior... FYI, using the technique you suggested, I was able to implement the macros used by the following example. However, I still have to assess if I can use the local member function macro with `this` (2nd usage below) due to the undefined behavior issue -- if not, I will just use the `this_` version of the macro (3rd usage below). class c { public: c(): x_(0) {} int get() const { return x_; } void f() { // Non-member local function. CONTRACT_AUX_LOCAL_FUNCTION_DECL( // Limitations: It cannot be template, etc. (int) (inc)( (int&)(x) (const int&)(delta) ) ) { // Func. definition outside macro so retain error line numbers. return x += delta; // No object. } }; // Extra `};` closes struct wrapping local function. int x = 0; int y = CONTRACT_AUX_LOCAL_FUNCTION_CALL(inc)(x, 10); // Member local function -- but implemention uses undefined behaviour. CONTRACT_AUX_LOCAL_FUNCTION_DECL( (int) (minc)( (c*)(this) (const int&)(delta) ) // Can be cv- qualified. ) { return x_ = get() + delta; // Implicit `this` as in member func. } }; y = CONTRACT_AUX_LOCAL_FUNCTION_CALL(minc)(this, 100); // Non-member local function with object parameter (implemetation does // not use undefined behaviour but user must explicitly use `this_`). CONTRACT_AUX_LOCAL_FUNCTION_DECL( // `this_` type `c*` can be cv-qualified. (int) (minc_)( (c*)(this_) (const int&)(delta) ) ) { return this_->x_ = this_->get() + delta; // Object via `this_`. } }; y = CONTRACT_AUX_LOCAL_FUNCTION_CALL(minc_)(this, 1000); } private: int x_; }; The #definitions of the `CONTRACT_AUX_LOCAL_FUNCTION_...` macros rely on a rather large number of helper macros so I could not show it here but you can find it at: http://dbcpp.svn.sourceforge.net/viewvc/dbcpp/branches/msvc/src/contract/aux_/local_function.hpp?revision=698&view=markup -- Lorenzo [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |