C++ Blog

C++ Concept Part 3

Posted in c++0x, templates by Umesh Sirsiwal on January 25, 2009

This is the last post in series of posts on C++0x concepts. In this we will look at C++0x concepts. The C++0x standard for concepts is almost identical to ConceptC++. The syntax are almost identical. Significant parts of ConceptC++ have become part of the draft standard.

One of the things we have not looked at the definition of concept map. In the previous example of sort, the template takes ForwardIterator as an argument. The article did not discuss what makes a forward iterator. Can we use an int* as a forard iterator? We have also said that ForwardIterator must has value_type argument. int* does not have a member value_type. But we want to pass int* as parameter to sort so that for example, we can sort an array of integers.

C++0x provides a way to solve this problem called concept_map. Using concept_map we can define what constitute ForwardIterator.

template ;
	concept_map ForwardIterator {
                                    // T*'s value_type is T
		typedef T value_type;
	};

Using above syntax we are saying that any T”*’s value_type is T. This removes need to wrap int* in another container.

In all C++0x concept provides solution for one of the biggest ongoing frustration with generic programming with C++. It will provide early and clear compilation errors for template users and authors both and bind them in template parameter contract.

Other C++0x sources on the web

Advertisements

C++0x Concepts Contd..

Posted in c++0x, templates by Umesh Sirsiwal on January 18, 2009

In previous article we had discussed BCCL. This post continues to discuss Concept with ConceptC++. The ConceptC++ was the playground for language level Concept ideas which eventually became part of currently proposed C++0x standard. In this post we take in-depth view to ConceptC++. These extensions were implemented by modifying GCC.

ConceptC++

Unlike the Boost Concept Check Library (BCCL), which is implemented purely using standard C++ constructs, these extensions are implemented by extending C++ language. By changing the C++ definition, it is possible to do things which was not possible otherwise. In particular, remember that with BCCL, it was not possible to make template parameter restriction part of template or function definition. With ConceptC++, this becomes now possible. In addition to enforcing restriction on instantiation of template, ConceptC++ also imposes restrictions on template implementation and makes sure that it only uses template parameter’s facility defined in the contract.

To understand ConceptC++, let us consider sum template which adds two parameters and returns the value:

template <typename T>
T sum(T a, T b){
   return a+b;
}

With Concept C++ we can rewrite this to:

template <CopyConstructable T>
T sum(T a, T b){
   return a+b;
}

This says T must be copy constructable. If we compile this template using ConceptC++ (even without any instantiation) we get the following error:

error: no match for 'operator+' in 'a+b'

That is because the template definition did not require T to implement operator+ but is trying to use it. This forces template signature to accurately define the template signature as:

template <CopyConstructable T>
  requires Addable<T>
T sum(T a, T b){
   return a+b;
}

In other words ConceptC++ puts restrictions on both template instantiation and template definition and binds them in a contract with respect to template parameter. This is what function, class or template definition, etc. are supposed to be.

We have been using magic words like CopyConstructable, Addable, etc. What are they? Are they new language features or are provided by library? What if we wanted to implement our own custom concepts? How will we go about that.

The C++ language addition provides capability to define new concepts while the library provides set of standard concepts. It is rather easy to build your own concept. For example let us look at definition of Addable concept:

auto concept Addable<typename T> {
  T operator+(T x, T y);
};

How simple can that be? The above definition is saying that the Addable concept implies that the template parameter must implement operator+ which takes two parameters of type T and returns T.

With this background, let us modify out example sort template. In case of sort, the template parameters are iterators and value pointed to by the iterator must implement less than operator. With ConceptC++ you can specify these restrictions as follows:

#include <concepts>
template<std::ForwardIterator T>
    requires LessThanComparable<T::value_type>
void sort(T b, T e)
{
  ....
}

As you can see ConceptC++ provides natural way of definining restrictions on template parameters allowing compilers to perform early error checking.


Performance


The ConceptC++ implements its functionality by reducing compile speed. However, just like BCCL the ConceptC++ does not incur any run time overhead.




	

Moving out

Posted in Uncategorized by Umesh Sirsiwal on January 17, 2009

I am moving this blog to a new home:

http://cppguru.techievarta.com/

Please update your links.

C++0x "Concepts"

Posted in c++0x by Umesh Sirsiwal on January 17, 2009

It is generally agreed that “Concept” is the biggest addition to C++ during C++0x (e.g. look @ Herb Shutter’s blog). The subject is large and I possibly cannot explain it in a single post. This post provides high level concept behind C++0x Concept.

Any person who has ever used C++ templates knows that compiler error messages when using templates are pain to understand. The problem stands from the fact that there is no easy way for template developers to define constraints on template parameters. For example let us consider the following example:

#include <vector>
#include <complex>
#include <algorithm>

int main()
{
     std::vector<std::complex<float> > v;
     std::stable_sort(v.begin(), v.end());
}

On my machine running GCC 4.2.1 it produces the following error:

/usr/include/c++/4.2.1/bits/stl_algo.h: In function âvoid std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â:

/usr/include/c++/4.2.1/bits/stl_algo.h:3176:   instantiated from âvoid std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3892:   instantiated from âvoid std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:11:   instantiated from here

/usr/include/c++/4.2.1/bits/stl_algo.h:2356: error: no match for âoperator<â in â__val < __first. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = std::complex<float>*, _Container = std::vector<std::complex<float>, std::allocator<std::complex<float> > >]()â

/usr/include/c++/4.2.1/bits/stl_algo.h: In function âvoid std::__merge_without_buffer(_BidirectionalIterator, _BidirectionalIterator, _BidirectionalIterator, _Distance, _Distance) [with _BidirectionalIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >, _Distance = int]â:

/usr/include/c++/4.2.1/bits/stl_algo.h:3182:   instantiated from âvoid std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3892:   instantiated from âvoid std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:11:   instantiated from here

/usr/include/c++/4.2.1/bits/stl_algo.h:3082: error: no match for âoperator<â in â__middle. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = std::complex<float>*, _Container = std::vector<std::complex<float>, std::allocator<std::complex<float> > >]() < __first. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = std::complex<float>*, _Container = std::vector<std::complex<float>, std::allocator<std::complex<float> > >]()â

/usr/include/c++/4.2.1/bits/stl_algo.h: In function âvoid std::__unguarded_linear_insert(_RandomAccessIterator, _Tp) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >, _Tp = std::complex<float>]â:

/usr/include/c++/4.2.1/bits/stl_algo.h:2362:   instantiated from âvoid std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3176:   instantiated from âvoid std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3892:   instantiated from âvoid std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:11:   instantiated from here

/usr/include/c++/4.2.1/bits/stl_algo.h:2309: error: no match for âoperator<â in â__val < __next. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = std::complex<float>*, _Container = std::vector<std::complex<float>, std::allocator<std::complex<float> > >]()â

/usr/include/c++/4.2.1/bits/stl_algo.h: In function â_ForwardIterator std::lower_bound(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >, _Tp = std::complex<float>]â:

/usr/include/c++/4.2.1/bits/stl_algo.h:3094:   instantiated from âvoid std::__merge_without_buffer(_BidirectionalIterator, _BidirectionalIterator, _BidirectionalIterator, _Distance, _Distance) [with _BidirectionalIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >, _Distance = int]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3182:   instantiated from âvoid std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3892:   instantiated from âvoid std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:11:   instantiated from here

/usr/include/c++/4.2.1/bits/stl_algo.h:3252: error: no match for âoperator<â in â* __first2 < * __first1â

Experienced C++ programmers may be able to figure out this error message however for most users it is extremely difficult. The error message is long and does not provide any insight in to cause of the error. The basic error is that  std:complex<float> does not model LessThanComparable which is required by std:sort.  In C++ there is no easy way for template developers to provide requirements on their parameters. Hence, compilers are not capable of testing the parameter errors early and provide meaningful error message. This C++ deficiency has significantly affected wider adaptation of templates and has resulted in development various methods of providing template parameter checks. These alternatives include both Language based and library based. C++0x Concepts will provide language level facility for error early error detection and meaningful error generation for template parameters.

It will probably take some time before MSVC and G++ support Concepts in their mainline languages. Till such time, existing alternatives may provide you with short term solutions.

Boost Concept Check Library

The Boost Concept Checking Library provides a library level concepts check facility without any language changes. Also the mechanism does not incur any run-time overhead. The checks are completely implemented at compile time. According to BCCL, it provides:

  • A mechanism for inserting compile-time checks on template parameters at their point of use.
  • A framework for specifying concept requirements though concept checking classes.
  • A mechanism for verifying that concept requirements cover the template.
  • A suite of concept checking classes and archetype classes that match the concept requirements in the C++ Standard Library.
  • An alternative to the use of traits classes for accessing associated types that mirrors the syntax proposed for the next C++ standard.

With BCCL the std::stable_sort can be written as:

template<typename T>
void sort(T b, T e)
{
  function_requires< LessThanComparableConcept<T> >();
  typedef typename
     std::iterator_traits<T>::value_type value_type;
  function_requires
     <LessThanComparableConcept<value_type> >();
  ....
}

With this change the error message changes to:

/usr/include/boost/concept_check.hpp: In member function âvoid boost::LessThanComparableConcept<TT>::constraints() [with TT = std::complex<float>]â:

/usr/include/boost/concept_check.hpp:48:   instantiated from âvoid boost::function_requires(boost::mpl::identity<T>*) [with Concept = boost::LessThanComparableConcept<std::complex<float> >]â

t.cc:13:   instantiated from âvoid mysort(T, T) [with T = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:21:   instantiated from here

/usr/include/boost/concept_check.hpp:314: error: no match for âoperator<â in â((boost::LessThanComparableConcept<std::complex<float> >*)this)->boost::LessThanComparableConcept<std::complex<float> >::a < ((boost::LessThanComparableConcept<std::complex<float> >*)this)->boost::LessThanComparableConcept<std::complex<float> >::bâ

/usr/include/c++/4.2.1/bits/stl_algo.h: In function âvoid std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â:

/usr/include/c++/4.2.1/bits/stl_algo.h:3176:   instantiated from âvoid std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3892:   instantiated from âvoid std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:15:   instantiated from âvoid mysort(T, T) [with T = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:21:   instantiated from here

/usr/include/c++/4.2.1/bits/stl_algo.h:2356: error: no match for âoperator<â in â__val < __first. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = std::complex<float>*, _Container = std::vector<std::complex<float>, std::allocator<std::complex<float> > >]()â

/usr/include/c++/4.2.1/bits/stl_algo.h: In function âvoid std::__merge_without_buffer(_BidirectionalIterator, _BidirectionalIterator, _BidirectionalIterator, _Distance, _Distance) [with _BidirectionalIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >, _Distance = int]â:

/usr/include/c++/4.2.1/bits/stl_algo.h:3182:   instantiated from âvoid std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3892:   instantiated from âvoid std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:15:   instantiated from âvoid mysort(T, T) [with T = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:21:   instantiated from here

/usr/include/c++/4.2.1/bits/stl_algo.h:3082: error: no match for âoperator<â in â__middle. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = std::complex<float>*, _Container = std::vector<std::complex<float>, std::allocator<std::complex<float> > >]() < __first. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = std::complex<float>*, _Container = std::vector<std::complex<float>, std::allocator<std::complex<float> > >]()â

/usr/include/c++/4.2.1/bits/stl_algo.h: In function âvoid std::__unguarded_linear_insert(_RandomAccessIterator, _Tp) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >, _Tp = std::complex<float>]â:

/usr/include/c++/4.2.1/bits/stl_algo.h:2362:   instantiated from âvoid std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3176:   instantiated from âvoid std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3892:   instantiated from âvoid std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:15:   instantiated from âvoid mysort(T, T) [with T = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:21:   instantiated from here

/usr/include/c++/4.2.1/bits/stl_algo.h:2309: error: no match for âoperator<â in â__val < __next. __gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = std::complex<float>*, _Container = std::vector<std::complex<float>, std::allocator<std::complex<float> > >]()â

/usr/include/c++/4.2.1/bits/stl_algo.h: In function â_ForwardIterator std::lower_bound(_ForwardIterator, _ForwardIterator, const _Tp&) [with _ForwardIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >, _Tp = std::complex<float>]â:

/usr/include/c++/4.2.1/bits/stl_algo.h:3094:   instantiated from âvoid std::__merge_without_buffer(_BidirectionalIterator, _BidirectionalIterator, _BidirectionalIterator, _Distance, _Distance) [with _BidirectionalIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >, _Distance = int]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3182:   instantiated from âvoid std::__inplace_stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

/usr/include/c++/4.2.1/bits/stl_algo.h:3892:   instantiated from âvoid std::stable_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:15:   instantiated from âvoid mysort(T, T) [with T = __gnu_cxx::__normal_iterator<std::complex<float>*, std::vector<std::complex<float>, std::allocator<std::complex<float> > > >]â

t.cc:21:   instantiated from here

….
….

/usr/include/c++/4.2.1/bits/stl_algo.h:3252: error: no match for âoperator<â in â* __first2 < * __first1â

Clearly a better error message (still a little longer than what we want it to be).

Although, BCCL provides better error message. The biggest drawback of the BCCL is that the restriction on the template parameter is not part of template prototype and hence not easily discoverable by algorithm user.  Language level support is needed to support that. The ConceptC++ was an experimental implementation of language level support. Significant parts of C++0x is derived from ConceptC++ and boost experimantation. I will discuss these changes in future posts.

C++ Proxy Template

Posted in templates by Umesh Sirsiwal on January 14, 2009

Earlier we had discussed Java Proxy class and had looked for ways to develop similar facility with C++. It turns out there is a rather easy way to provide such a facility. If you have used smart pointers, you have already used one form C++ proxy template. Smart pointers essentially provide a proxy facility. Bjarne Stroustrup covered this subject in this paper.

The key to the wrapper definition is that the fact that all objects created on the stack are eventually destroyed when the object goes out of the scope. For example:

class Test{
    void method(){
         X a;
       // Implementation
       return;
     }

}

In the above case the X’s destructor is called when Test::method returns due to return call or exception.

Now let us use this knowledge to define the Wrap class. Let us first define the prefix, suffix and the wrapped class:

#include <iostream>
 using namespace std;
 void prefix() { cout << "prefix\n" }
 void suffix() { cout << "suffix\n"; }

// The person class looks like this:

class Person{
  std::string mName;
  Person(std::string pName): mName(name){}
  void printName(){
     std::cout << mName << std::endl;
  }

};

Now we can define the Wrap class as the following:

template <class T >
class Wrap {
     T * p ;
     public:
             Wrap (T * pp ) :p (pp) { }
             Call_proxy <T> operator ->() {
                   prefix ();
                   return Call_proxy<T>(p);
             }
};
template <class T >
class Call_proxy {
       T * p ;
       public :
              Call_proxy (T * pp ) :p (pp ){ }
              ˜Call_proxy () {
                     suffix ();
               }
               T * operator ->() {
                          return p ;
                }
 };

We can now wrap any object  of type T in the Wrap class. For example: we can take class Person and wrap it like Wrap<Person> person(new Person);

Any dereferencce of person using -> operator, results in call to operator-> of Wrap class. The method calls the prefix function , creates a new object of type Call_proxy containing the pointer to object. The method is called. On return from the method, Call_proxy is destroyed which implicitly results in call to suffix().

Let us test it. the following code snippet:

Wrap<Person> person(new Person("test"));
person->printName();

should print:

prefix
test
suffix

Rather straightforward and elegant to use. But, syntatic sugar to implement.

Note that suffix will be called even if the method returned due to exception.  This is better than Java, where the programmer has to take explicit action to make sure suffix is called in case of exception.

The Stroustrup’s paper also covers other issues like ownership, parametrization etc.  In most cases you may not need to worry about those. If you need to, take a look at the paper.

Happy proxying!

Template or not to Template

Posted in templates by Umesh Sirsiwal on January 10, 2009

As I was learning C++ over an year ago,  I bought Modern C++ Design by Andrei Alexandrescu. As I read through the book, I was simply amazed by power offered by templates. Experience with the book was followed by Boost libraries. Specifically boost lambda and what it could provide to programmer. These went way beyond traditional STL use of templates. This excitement with C++ templates was followed by my experimentation with using templates in my own projects.  This post summarizes  experiences with templates.

  • Templates provide power with efficiency: Templates provide a lot of power without compromising efficiency. The Andrei’s book is full of examples of such power. A quick look inside the boost library provides examples of such power. Look at simple construct like boost::any which allows you to hold any type of data in it so that you can create a container/array which can hold boolean, integers, your various classes, etc. all at the same time. You can also look at a lot more complex construct like boost::lambda library which brings lambda programming to C++. Recently the boost has added boost::proto discussed in a seperate post on this site. The power really exists. Using these libraries can make your programming life a lot simpler. It is natural tendency to write your own templates on the same line. Should you or shouldn’t you?
  • Templates are not well understood: The templates are not well understood yet. Most experienced C++ programmers find it hard to understand how to program templates. At present templates are a the stage as Object Oriented Programming was several years ago. The compilers have progressed to state where they can correctly compile templates. However, the power of templates is yet to be distilled in to developer community at large. So if you decide to use templates, please be patient and give plenty of time for developers to learn and get up to speed.
  • Template debugging is horrifying experience for first time users: Error messages produced by compiler are horrifying large and complex. For simplest of errors, one gets 3 pages long error message with actual error who knows where. Once you get used to of debugging compilation issues you can generally figure out the error but it takes time to get used to of those errors. Template adaption will go a long way if the compilers start producing better error messages. But if you think compiler was the only issue just wait till you get to debuggers. The debuggers have not yet found a good way to deal with templates. Last but not least is compile time with templates. With most compilers, templates have to be included in header files. A simple change in the template requires compilation of all of your code which uses templates. This is like going backward on libraries.

In my experience, templates offer a lot of power and flexibility without compromising efficiency. The compilers can mostly deal with templates correctly. However debugger, compiler errors, and ways to reduce compile time can go a very long way in helping wider adaptation of templates. But if you are one of those early adapters and technology enthusiast, go ahead experiment and adapt templates and it will go a long way in helping your projects.

If you are going to use templates, you should start off by reading C++ FAQ Lite on template.

Java Style Dynamic Proxy in C++

Posted in c++0x by Umesh Sirsiwal on January 9, 2009

This post defines C++ template based implementation for C++ proxy.

I recently came across Java’s proxy object. That is some cool technology. Using this one can wrap one object in another object in a completely typesafe way. From user’s point of view, the proxy object looks something like:

ProxiedObjectInterface obj = (ProxiedObjectInterface)ProxyCreator.newInstance( proxiedObject );

More details on proxy object are available here.

Since the interface exposed is of the proxied type, all calls to obj are typsef and can be checked by compiler. In java ProxyCreator class does not need to know anything about proxied object. This makes it very powerful.

I have been wondering if there is any easy way to create a similar facility in C++. I cannot think of one right away. I know we can do some cool things with template meta-programming. What will that be?

Tagged with: , , ,

Domain Specific Embedded Langauge

Posted in boost by Umesh Sirsiwal on January 6, 2009

We typically program in a general purpose programming language like C, C++, Java, Perl, etc. These languages are designed to solve all the problems of the world and no problem in particular. However, it will be a lot more elegant if sound processing library exposed a sound specific language, an image processing library exposed an image processing specific language not just API calls which is the case currently. In effect these will enhance overall general purpose language. These languages are called Domain Specific Embedded Language (DSEL).  For example:

result  = src * dest;

should multiply two numbers for arithmetic domain. For images, it may layer the two images, for music this expression may allow mixing of the two tunes. As you probably know, in C++ this can easily be achieved using operator overloading. But, the DSELs probably want to be significantly more expressive than depicted above. C++ is probably the best language for defining a DSEL since it allows rich set of operator overloading and metaprogramming constructs to implement your language. This article compares various programming language’s capability to define DSEL.

It is possible to define a complete DSEL manually in C++. However, anything beyond overloading of small set of operators can be time consuming. Boost 1.37.0 now includes Boost.Proto. The Boost.Proto provides facilities to quickly develop DSEL. From Boost.Proto documentation:

Expression Templates are an advanced technique that C++ library developers use to define embedded mini-languages that target specific problem domains. The technique has been used to create efficient and easy-to-use libraries for linear algebra as well as to define C++ parser generators with a readable syntax. But developing such a library involves writing an inordinate amount of unreadable and unmaintainable template mumbo-jumbo. Boost.Proto eases the development of domain-specific embedded languages (DSELs). Use Proto to define the primitives of your mini-language and let Proto handle the operator overloading and the construction of the expression parse tree. Immediately evaluate the expression tree by passing it a function object. Or transform the expression tree by defining the grammar of your mini-language, decorated with an assortment of tree transforms provided by Proto or defined by you. Then use the grammar to give your users short and readable syntax errors for invalid expressions! No more mumbo-jumbo — an expression template library developed with Proto is declarative and readable.

In short, Proto is a DSEL for defining DSELs.

Boost.Proto uses template meta-programming to implement the help bild DSELs quickly and efficiently. Boost.Proto can be slightly overwhelming for the first time users and specifically those who are not used to of templates meta-programming. If you want to use Boost.Proto remember to read the user’s guide a couple of times before trying it out.

Good luck.

Happy DSELing.

Shared Memory based C++ programming

Posted in boost by Umesh Sirsiwal on January 5, 2009

When it comes to shared memory based programming, we C++ users have traditionally found our selves at disadvantage. Most our beloved constructs like shared pointers, various containers, scoped locks, etc. don’t work very well when programming in C++. In addition, we cannot place objects which use inheritance in shared memory since the virtual pointers cannot work in shared memory. These limitation has implied that the shared memory is rarely used in C++ programming. Whenever it is used, the object placed in the shared memory are more like C constructs rather then C++ constructs. This is pity since using shared memory provides significant performance advantage in certain conditions.

Boost 1.35 includes Interproces which provides C++ based programming environment for shared memory. The facilities provided are:

  • Shared memory based pool of memory and capability to new C++ objects from this pool
  • Mutexes placed in the shared memory
  • Various smart pointers
  • Various STL-like containers which can be placed in shared memory. These containers include maps, deque, set, list, flat_map, flat_set, slist, and string

In addition various boost containers can be placed in shared memory. These containers include the multi-index container.

Hopefully these constructs make placing objects in shared memory a little easier for you all. Please note that placing data in shared memory has traditionally been dangerous due to complexity in debugging crashes, not easily understood deadlocks, etc. Please use shared memory based containers carefully.

C++ Monitor Pattern

Posted in boost by Umesh Sirsiwal on January 5, 2009

Locking is an integral part of concurrent programming. A usual class used with threads looks like:

class A {
void F() {
ScopedLock l(m);
....
....
}
Void G()
{
ScopedLock l(m);
....
....
}
mutex m;
};
This guarantees that the class data part of class A are always protected from multiple thread access. However, this code is fragile and difficult to maintain. It moves the responsibility of maintaining concurrency to the class writer. Also, sooner or later somebody will make a change of the following form:

Void G()
{
ScopedLock l(m);
....
....
F();
}

This will deadlock unless you were using recursive mutex.

Also, a construct like this is difficult to use if you are trying to use third party library like STL. For example, let us say you were using std::map. In order to enforce appropriate concurrency control you must wrap every map method you are going to use with a lock that implies you must implement a forwarding class which takes the user argument performs a lock and then call the map function. This is tedious, time consuming and absolute waste of time.

Won’t it be nice if there was a way to generically wrap class and provided method forwarders? The forwarder will provide the lock/unlock capability and the class implementer will not have to worry about concurrency issues. Welcome to monitor pattern. This pattern was first introduced in this paper by Douglas Schmidt.The monitor object guarantees that only one method runs within an object at any given point of time. Because the monitor pattern guarantees that there is any need to perform locking within class methods.

One of the C++ monitor pattern implementation is part of libpoet. ACE provides another implementation of the monitor pattern. I am sure there are other implementations. The libpoet implementation is partially based on the this paper by Bjarne Stroustrup. The library includes two implementations of the monitor pattern. One is based on smart pointer and the other is based on inheritance and has additional functionality. In most cases the pointer based implementation is sufficient and is considered in this post.

The monitor pointer is implemented as smart pointer and is called monitor_ptr. Like any other smart pointer it provides an object wrapper. The wrapper in this case takes a lock before the object is called and releases the lock once the object call is complete.  To use the class A defined above with monitor_ptr we will remove the locks from the class and wrap A as follows:

poet::monitor_ptr<A>  a(new A);

Now calls to  a->F() and a->G() will result in automatic locks taken by the monitor_ptr and call to G() will wait till call to F is complete.

class A {
void F() {
....
....
}
Void G()
{
....
....
}
};
Look no locks. If we need to use a map with concurrent programming we will write something like:

poet::monitor_ptr< std::map<int, std::string> > m(new  std::map<int, std::string>);

We will now access the monitored map using something like:

m->insert(1,std::string("abc"));

without worrying about the locking.

The inheritance based implementation provides additional functionality since it can use condition wait constructs.

Of course it will be much nicer to have a language level support (similar to synchronized keyword in Java) for the monitor pattern. That is a lot more elegant but till the language supports it we will have to live with the smart pointer based implementation.