|
Boost : |
From: John Torjo (john_at_[hidden])
Date: 2003-05-25 02:40:37
> On Fri, 23 May 2003 13:00:57 +0300, "John Torjo" <john_at_[hidden]>
> wrote:
>
> >Hi all,
> >
> >While working on smart_assert, I created a class that should ensure
calling
> >a global function before main (a static_initializer).
>
> Well, about "ensuring"... 3.6.2/3 of the standard.
>
> >
> >It does not work for either VC6 nor for gcc3.2.
>
> What compilers does it work with?
None I have tested it with ;-)
>
> >Do you have any idea of a workaround?
> >
>
> Relying on dynamic initialization of an object at namespace scope puts
> you under the limitations of 3.6.2/3. Under those conditions you can
> simply do
>
> const int n = (f(), 1);
I suppose you mean at global scope.
But if this is within a header file, f() might be called multiple times.
What I want, is f() to be called ONCE, before main().
>
> without any helper class or class template. If there are reasons to
> use the class template, as you did, it's important to consider that
> the standard prohibits instantiations of template static data members
> (and nested classes) definitions that are not "necessary" (see
> 14.7.1). One way to force that instantiation is to take the address of
> the static data member. Another way should be to explicitly specialize
> the static data member itself for the function f (I'm not 100% sure
> though):
>
1.9/7
Accessing an object designated by a volatile lvalue (3.10), modifying an
object, calling a library I/O
function, or calling a function that does any of those operations are all
side effects, which are changes in the
state of the execution environment. Evaluation of an expression might
produce side effects. At certain
specified points in the execution sequence called sequence points, all side
effects of previous evaluations
shall be complete and no side effects of subsequent evaluations shall have
taken place.
-------
3.6.2/3 - footnote 31)
An object defined in namespace scope having initialization with sideeffects
must be initialized even if it is not used (3.7.1).
So, I used a volatile:
---------- code
#include <iostream>
typedef void (*void_func)();
template< int i>
struct void_initializer_internal {
static volatile void_func m_f;
};
template< int i>
volatile void_func void_initializer_internal< i>::m_f;
template< void (*f)()>
class void_initializer {
public:
void_initializer() {
void_initializer_internal< 1>::m_f = &f;
}
struct internal {
internal(int i) {
void_initializer_internal< 1>::m_f = &f;
if ( i != 0)
f();
}
};
static internal s_internal;
};
template< void (*f)()>
void_initializer< f>::internal void_initializer< f>::s_internal = 1;
void f() {
std::cout << "f()" << std::endl;
}
int main() {
// does NOT call f() !!!
void_initializer< &f> v;
std::cin.get();
return 0;
}
---------- ENDOF code
I've probably misunderstood something, since f() is still not called.
I've tested it with VC6/gcc3.2.
Can anybody test it with other compiler(s), and let me know if it works?
Best,
John
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk