Skip to main content

Posts

Faster meta-programs using gcc 4.5 and C++0x

One of the practical issues with C++ meta-programming is its speed. C++ programs that use heavy meta-programming can be notoriously slow to compile on contemporary compilers. Things are changing, however. Check the following comparison of gcc 4.5 against gcc 4.4.3. The first graph is obtained from a program that creates a binary tree of template instantiations. The x-axis shows the number of instantiations when value of N goes from 8 to 17. I could not build up patience for gcc 4.4.3 beyond 16363 instantiations (N=13). On the other hand, gcc 4.5 does pretty good and its increase in compilation time is indeed linear as mentioned here . Here is the program that creates a binary tree of template instantiations. template <int Depth, int A, typename B> struct Binary { enum { value = 1 + Binary<depth-1, 0, Binary>::value + Binary<depth-1, 1, Binary>::value }; }; template<int a, typename B> struct Binary<0, A, B> { enum { value = 1 }; ...

Modifying temporaries

Temporary objects are created and destroyed all the time in a C++ program. A simple example would be a function that returns by value. A temporary is as good as a const object because it makes little sense (usually) to change a temporary object, which is unnamed and has a very short time span. (Note: A temporary can be bound to a const reference in which case the scope of the temporary is the same as that of the reference.) However, as it turns out, in C++ you can change temporaries ... if they are of class type! You can call non-const member functions on a temporary. This is quite similar to binding a temporary to a non-const reference and changing it. Section 3.10.10 in C++ ISO/IEC 14882:1998 standard clearly mentions this exception. There are at least two practical use of such an exception. One is the " Named Parameter " idiom and the other one is the Move Constructor idiom . In case of the named parameter idiom, the member functions might prefer to return the object by no...

LEESA: A new way of typed XML programming in C++

Some of my recent research work has focused on developing a highly generic and reusable library for complex object structure traversal, which is best exemplified by schema driven XML programming. I'm glad to present a research paper called LEESA: Embedding Strategic and XPath-like Object Structure Traversals in C++ , which will be published in the proceedings of IFIP Working Conference on Domain Specific Languages (DSL WC) , 2009 at Oxford, UK. LEESA stands for L anguage for E mbedded qu E ry and traver SA l. LEESA has advanced the state-of-the-art of the typed XML programming in standard C++ to a level where many benefits of static type analysis can be maintained while enjoying a succinct syntax similar to that of XPath. Below, a quick motivating example of LEESA that sorts and prints the names of the authors in a XML book catalog is shown. Catalog() >> Book() >> Author() >> Sort(Author(), LastNameComparator) >> ForEach(Author(), print); The key thing to ...

Int-to-type idiom and infinite regress

A new writeup on Int-to-type idiom has been posted on More C++ Idioms wikibook. It is used to achieve static dispatching based on constant integral values. I'll finish the writeup of the idiom here with special attention to how int-to-type idiom can lead to infinite series of type instantiations and why. The idiomatic form of the Int-to-type idiom is given below. template <int I> struct Int2Type { enum { value = I }; typedef Int2Type<I> type; typedef Int2Type<I+1> next; }; The type typedef defined inside the template is the type itself. I.e, Int2Type ::type is same as Int2Type . The next typedef gives the following type in order. However, compiler is not required to instantiate the next type unless and until two things happen: (1) an instance of the type is created or (2) an associated type is accessed at compile-time. For example, Int2Type will be instantiated if one the following two things are written. Int2Type<10> a; // a variable declaration...

copy elision and copy-and-swap idiom

An updated writeup of the copy-and-swap idiom is now available on the More C++ Idioms wikibook. A comparison of two different styles of assignment operator is shown. First version accepts the parameter as pass-by-const-reference whereas the second version accepts it as pass-by-value . For some classes pass-by-value turns out to be more efficient as a copy of the object is elided when the right hand side is a rvalue.

linked list using std::pair (infinite regression)

Defining a node of a linked-list using std::pair sounds as simple as drinking a Starbucks's white chocolate mocha. But it really isn't. Give it a try! The constraint is to use std::pair's first or second as a pointer to the structure itself, like in any linked-list's node. As far as I know, it is impossible unless you resort to ugly casts from void pointers. The problem is actually quite well known and gives rise to something known as infinite regress , where the problem you want to solve reappears in the solution to the problem. typedef std::pair<int, /* Pointer to this pair!! */ > Node; The closest thing I could come up with is something like the one below. struct Node : std::pair <int, Node *> {}; Node n; n.second = &n; // A cyclic linked-list.

return void

I thought it would be interesting to discuss a subtle C/C++ interview question I learned recently. Question is deceptively simple: "Can you write a return statement in a function that returns void?" The answer is "Yes! You can return void!" The following program seems to be a valid C/C++ program. static void foo (void) { } static void bar (void) { return foo(); // Note this return statement. } int main (void) { bar(); return 0; } I tested it using gcc4 and VS9. With -ansi and -pedantic compiler options for gcc, it throws just a warning pointing at line #5. return_void.c:5: warning: return with a value, in function returning void Although use of such a feature is not clear in a C program, it is particularly useful while using templates. Consider, template <class T> T FOO (void) { return T(); // Default construction } template <class T> T BAR (void) { return FOO<T>(); // Syntactic consistency. Same for int, void and everything else. } int m...

RSS Feed for More C++ Idioms Wikibook

The open-content wikibook "More C++ Idioms" has grown quite a bit from it inception. Whenever I get time, I try to add more contents in the book. So I always wanted to track the changes happening in the book in a convenient manner. Today, I put together a RSS feed for the book, which publishes recent changes made to the book. Thanks to the excellent technical support provided by existing wikibookians (if that is a word). The feed is formatted like two column GUI-based diff utilities (kdiff3, Beyond-compare). Frankly, it is not as readable and enjoyable as regular blog entries but at least it will help interested readers to know what new content is being added to the book and how the book making progress towards completion.

Redirecting C++ Truths feed

Dear readers, Thanks for your continued interest in the C++ Truths blog and a steady stream of feedback comments. For quite some time now, I'm interested in learning accurate statistics about the readers of this blog. Recently, I came across, FeedBurner , which seems to be a popular choice for centralized feed processing and maintaining feed analytics such as subscriber count, live hits and many more things. Therefore, I have decided to redirect all the future contents on C++ Truths blog to the CppTruths feed. Existing atom and rss feeds shall be discontinued soon. I encourage you to subscribe to the new feed source and help me find the real subscriber count. In return, I promise to be more regular and frequent in posting more C++ truths, which you love to read!! - Sumant.

Function Template Overload Resolution and Specialization Anomaly

I recently realized that function template overloading and function template specialization can interact with each other in complex ways giving rise to quite surprising C++ programs. Consider, template<class T> // (a) a base template void f( T ) { std::cout << "f(T)\n"; } template<> void f<>(int*) { // (b) an explicit specialization std::cout << "f(int *) specilization\n"; } template<class T> // (c) another, overloads (a) void f( T* ) { std::cout << "f(T *)\n"; } int main (void) { int *p = 0; f(p); } Output of the above program is "f(T *)" (i.e. (c) is invoked in main). Now simply swap the order in which (b) and (c) are written. The output of the program changes! This time it invokes (b) giving output as "f(int *) specilization". The reason behind it is that when the integer full specilization (b) of f is defined in the order shown above, it is a full specialization of (a). But (c)...

using std::copy on std::map iterator pair

Sometimes it is useful to be able iterate over all the elements of a std::map using standard algorithms like std::copy(), std::count(), std::min_element(), std::max_element(). These standard functions do not work out of the box using std::map::iterator. For example, if you want to print all the elements of a map to standard output, you can't use the following popular copy-ostream_iterator idiom. std::map <std::string, int> m; std::copy (m.begin(), m.end(), std::ostream_iterator<int>(std::cout, "\n")); // does not compile This is because value_type of the map::iterator is a pair. In other words, if iter is a map<T,U>::iterator then *iter gives pair<T,U> and not U. If we could somehow get hold of pair::second (i.e. type U) instead of pair<T,U> all the above mentioned algorithms can be used out of the box. The approach I took to solve this problem is to write an iterator adaptor that behaves likes any general bidirectional_iterator. In general, ...

New book on modern C++ idioms

For quite some time now, I am hoping to come across a book on modern C++ idiom as comprehensive as the Purple book by James Coplien! Finally, I got bored of the long wait and a thought came to my mind - This is Web 2.0 and open knowledge era. Why don't I start writing myself? and ask the world to contribute to it? So here we go! A new free, open book on modern C++ idioms called More C++ Idioms is taking shape on en.wikibooks.org And everyone's invited!

const overload functions taking char pointers

Always have two overloaded versions of functions that take char * and const char * parameters. Declare (but don't define if not needed) a function that takes const char* as a parameter when you have defined a function that accepts a non-const char* as a parameter. #include <iostream> #include <iomanip> static void foo (char *s) { std::cout << "non-const " << std::hex << static_cast <void *>(s) << std::endl; } static void foo (char const *s) { std::cout << "const " << std::hex << static_cast <void const *>(s) } int main (void) { char * c1 = "Literal String 1"; char const * c2 = "Literal String 1"; foo (c1); foo (c2); foo ("Literal String 1"); //*c1 = 'l'; // This will cause a seg-fault on Linux. std::cout << c2 << std::endl; return 0; } Because of default conversion rule from string literal to char *, the call to foo using in-pla...

Future of C++ track @ ACCU

Recently held ACCU 2007 conference had a track dedicated to C++ called: Future of C++ Track. I have listed the presentations in that track and some other related presentations for a quick reference. * An Outline of C++0x (Bjarne Stroustrup) * Generalizing Constant Expressions in C++ (Jens Maurer) * C++0x Initilaisation: Lists and a Uniform Syntax (Bjarne Stroustrup) * An Introduction to the Rvalue Reference in C++0x (Howard Hinnant) * C++ has no useful purpose (Russel Winder) * C++ Modules (David Vandevoorde) * Support for Numerical Programming in C++ (Walter Brown) * C++ Threads (Lawrence Crowl) * Standard Library report (Alisdair Meredith) * Concepts: An Introduction to Concepts in C++0x (Doug Gregor) ( OOPSLA06 paper )

iterator tags idiom and compile-time algorithm selection

Compile-time algorithm selection can be done using function overloading and traits idiom . It is a quite useful technique in generic programming. In this technique usually a set of "selector" types are used to select one among many overloaded functions. Note that the number of parameters to these overloaded functions is same but there is a "selector" type at the end of the parameter list. A use of that technique based on standard defined iterator tags is shown here .

Use of std::bad_exception

std::bad_exception is a useful device to handle unexpected exceptions in a C++ program , which works in conjunction with unexpected_handler. unexpected_handler and terminate_handler are a traditional way of dealing with unknown exceptions. std::set_unexpected () and std::set_terminate () functions let us register custom handlers instead of standard handlers, which usually abort the program. More information can be found here . Assuming g++ 4.0.2 complies with the standard in this area, I verified that if function f() throws an exception that is not listed in its exception specification list, our custom function pointed to by the unexpected_handler is invoked if we have set one. If our custom handler rethrows whatever unknown exception caused the unexpected() to be invoked, following things happen. * If the exception specification of f() included the class std::bad_exception , unexpected() will throw an object of type std::bad_exception, and the C++ run time will search for another...

Boost C++ Idioms

This time lets take a brief look at some nifty C++ idioms in the Boost peer-reviewed libraries. We will talk about Boost Base-from-Member idiom, Boost Safe bool idiom, Boost Named External Argument idiom, Boost Non-member get() idiom, Boost Meta-function wrapper idiom, Boost Iterator pair idiom, and the Boost Mutant idiom. Boost Base-from-Member idiom This idiom is used to initialize a base class from a data-member of the derived class. It sounds contradictory to the rules of C++ language and that is the reason why this idiom is present. It basically boils down to pushing the parameter data member in a private base class and put that private base class before the dependent base class in the derivation order. A generalization of the technique can be found here . Boost Safe bool idiom Many authors have talked about the evils of type conversion functions defined in a class. Such functions allow the objects of that type to participate in nonsensical expressions. One good example is in sta...

new, delete, custom memory allocation, and exception safety

This post will hopefully push you ahead to a higher level of expertise in memory management mechanics of C++ and exception safety. Here we go... Some warm-up: Consider a function void func (T*, U*); and int main() { func (new T, new U); // line 1 } Calling the function like in line 1 is a bad idea because parameter evaluation sequence is not standard and therefore it memory allocation of second new (it could T or U) fails, we have a blatant memory leak. What to do? Lets use our silver bullet: auto_ptr! but it fails too for the same reasons. Consider a function void func (std::auto_ptr <T>, std::auto_ptr <U>); Now it is possible that, even before any auto_ptrs are constructed, new may throw or a constructor may throw and all efforts go in vain. Details can be found in Hurb Sutter's More Excetional C++: Item 20-21. So we should separate the allocation and the function call. auto_ptr <T> t1 = new T; auto_ptr <U> u1 = new U; func (t1, u1); That's no better e...

Non-Virtual Interface (NVI) idiom and the design intent

Assuming that the philosophy of Non-Virtual Interface (NVI) idiom is strictly adhered I came up with a table that summarizes the design intent in terms of access modifiers and virtuality. Strict adherence of NVI allows separation of the interface of a class into two distinct interfaces: client interface (public non-virtual) and subclass interface (protected virtual/non-virtual). Such a structure helps mitigate the Fragile Base Class (FBC) Interface problem if discipline is followed. Its only downside is a little bit of code bloat. More about this approach of resolving FBC can be found here .   non-virtual virtual but not pure pure virtual without body pure virtual with body Public Clients expect substitutability. Extension points are encapsulated.  Subclasses should stay away from this if an equivalent protected function using NVI is given. Clients expect substitutability. Extension points are visible. Subclasses can option...