From: Lorenzo Caminiti on
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
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
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
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
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! ]