views:

96

answers:

3

Is this portable or at least safe to use with g++?

#include <iostream>
#include <vector>

struct c {};
std::vector<c*> v;
struct i : c { i () { v.push_back (this); } } a, b, c;

int main () {
  std::cout << v.size () << "\n"; // outputs 3 with g++
}

EDIT:

Ok, what I need turned out to be a bit harder: The same code with templates:

#include <iostream>
#include <vector>

template < typename T > struct c {};
template < typename T > struct cv { static std::vector<c<T>*> v; };
template < typename T > std::vector<c<T>*> cv<T>::v;
template < typename T > struct i : c<T> { i () { cv<T>::v.push_back (this); } };

cv<int> dummy; // even this won't initialize cv<int>::v
i<int> a, b, d;

int main () {
  std::cout << cv<int>::v.size () << "\n"; // outputs 0 :-(
}

How could I fix this to work as above?

EDIT 2:

Here is an ugly fix with macros (I hope there is a better way to do it):

#include <iostream>
#include <vector>

template < typename T > struct c {};
template < typename T > struct cv;
#define INITCV(X) \
  struct v##X { static std::vector<c<X>*> v; }; \
  std::vector<c<X>*> v##X::v; \
  template <> struct cv<X> { typedef v##X V; }
template < typename T > struct i : c<T> { i () { cv<T>::V::v.push_back (this); } };

INITCV(int);
i<int> a, b, d;

int main () {
  std::cout << cv<int>::V::v.size () << "\n"; // outputs 3 again :-)
}

(BTW, should I have posted a new question instead of the edits?)

+4  A: 

Globals in a translation unit (usually that corresponds to a .c file) are initialized in order, so this is safe. You only get problems is you have globals in different object files that depend on each other.

This is specified in the standard in §3.6.2/2:

Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit.

Global variables have ordered initialization as long as they aren't declared static.

sth
Thank you for looking that up in the specification. Unfortunately, this does not seem to apply to templates, as in my modified question.
Thomas
+2  A: 

Order guaranteed yes.

Safe: Questionable. Depends what you mean by safe.
But as written it is portable and will not crash on any compiler I know.

Martin York
A: 

For your updated question, I haven't waded through the standard to find out when members of implicitly-instantiated templates are supposed to be initialized, but explicit instantiation does seem to be the solution:

template class cv<int>; // Not a dummy. Declares the template like a class.

Standardese at 14.7.2/7:

The explicit instantiation of a class template specialization implies the instantiation of all of its members not previously explicitly specialized in the translation unit containing the explicit instantiation.

Potatoswatter