Browse DevX
Sign up for e-mail newsletters from DevX


Enforcing Compile-time Constraints-2 : Page 2




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Presenting the Problem
Suppose your app needs to interface with a non-C++ module written in C or SQL. To do so, you need to ensure that all objects passed to the non-C++ module have POD types. Alas, the definition of a POD type is rather evasive:

struct S1 { int x;}; class S2 { public: void func(); }; union S3 { struct { int x, y; } t; char c[4];}; struct S4 : S1, S2 {};

The above are all POD types. However, the following aren't:

struct C1 { virtual void func(); //has a virtual function }; struct C2 { struct T{ int x, y; }; ~C2(); //has a destructor }; struct C3 : virtual S1 {} ; //has a virtual base class

Several programming idioms rely on the distinction between POD and non-POD types. The standard macro offsetof() (defined in <csstddef>) is an example. The following expression:

size_t nbytes = offsetof (S, mem);

returns the offset in bytes of the member mem. According to the C++ standard, S must be a POD class, struct, or union. Otherwise, the results are undefined. Your task is therefore to write a constraint that automatically distinguishes between POD and non-POD types at compile-time. When the "must be POD type" constraint is violated, the compiler should issue an intelligible error message.

Implementing a Constraint
A constraint is essentially an expression or declaration within a member function of a class template. When the constraint is violated, the said expression triggers a compilation error. The challenging part is to find the right compile-time expression(s) that will fire when the constraint is violated. Familiarity with the C++ standard certainly wouldn't hurt here. Fortunately, the standard states in clause 9.5 that a non-POD object shall not be a member of a union. Eureka! Take advantage of this restriction by creating a union whose sole member is the object you want to test:

template <class T> struct POD_test { POD_test() { union { T t; //T must be a POD type } u; } };

Compilers generate code only for member functions that are actually called, either implicitly or explicitly. Therefore, implementing the constraint inside the constructor or destructor of a class template will guarantee its compile-time evaluation in every instance (later we will see how to improve this design).

To test the code, instantiate as many specializations as you like using diverse template arguments:

//the following three pass compilation POD_test <int> pi; POD_test <S1> ps1; POD_test <S4> ps4; //these ones fail POD_test <std::string> pstr; POD_test <C1> pc1; POD_test <C2> pc2;

As expected, the compiler issues error messages for the last three instances because their template arguments aren't POD objects.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date