Skip to content

Implementing C++ designated initializers with templetized constructor

C99 facilitates support designated initializers:

struct XYZ {
	int x,y,z;
};

static const struct XYZ zyx = {
	.z = 1, .y = 2, .x = 3
};

static const struct XYZ yxz = {
	y : 1, x : 2, z : 3
};

I found this handy feature very useful, since it does not require remembering order of the struct fields and simplifies refactoring and/or evolving of the existing code.
C++0X and C++1X does not allow this (please follow this link for more details)
This page has inspired me on a practical solution to this problem.

The solution is in templetization of the structure and providing ad-hoc template specialization constructor:

template<int N>
struct XYZ {
	int x,y,z;
	inline XYZ() {} // fall-back constructor implementation
};

template<>inline XYZ<1>::XYZ()
	: z(1), y(2), x(3) {}

static XYZ<1> zyx;

static const int a = 1, b = 2, c = 3;

template<>inline XYZ<2>::XYZ()
	: x(a), z(b), y(c) {} // Not possible in C99

static XYZ<2> xzy;

Compiler may complain about wrong order of initialization, but that the intent is.
GCC can be instructed to ignore this error with a pragma:

#pragma GCC diagnostic ignored "-Wreorder"

This approach, however, disables struct initialization with brace enclosed lists:

static XYZ<0> xyz = { 1, 2, 3}; // Does not compile

The struct XYZ now have a constructor and is not recognized as an aggregate anymore (see for definitions)

To have option for both designated and brace-encoded initializers the template can be specialized

template<>
struct XYZ<0> {
	int x,y,z;
};

static XYZ<0> xyz = { 1, 2, 3 };

Although, this kind of specialization has one drawback – definition of XYZ is now present in two variants.

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*

*