Showing posts with label boost. Show all posts
Showing posts with label boost. Show all posts

Tuesday, August 16, 2011

Using SFINAE to recurse into collection types

Last week, during an interview, I have been asked about TMP. The question was "How would you create a function that takes a vector and prints it to the console ? It should do so recursively."

I though about SFINAE and using type traits, but was totally unable to come up with code. I never wrote any TMP code, in fact, I just read some books and articles about it. So the interviewer came up with his solution, which was to embed to type argument into a function parameter template, and create a "default function" for built-ins. That would look like that:

template <typename T> void print_r(const T& t) {
  std::cout << t;
}
 
template <typename T> void print_r(const std::vector<T>& v) {
  typedef typename std::vector<T>::const_iterator iter_t;
  for(iter_t iter = v.begin(); iter != v.end(); iter++)
    print_r(*iter);
}

Yes, of course it works. But the problem here is that it only works for std::vector, and you would have to write such a function for every collection type in the template library. Not sexy. And C++ does not have a generic collection hierarchy like C# has (which would be stupid anyway.) Since I won't give up so easily, I wrote my code using SFINAE. These functions detects the presence of const_iterators and recurse into the collection if such a type is present :

template <typename T>
struct has_const_iterator {
  typedef char yes[1];
  typedef char no[2];
 
  template <typename C>
  static yes& test(typename C::const_iterator*);
 
  template <typename>
  static no& test(...);
  static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
 
template <typename T> void print_r(const T& t, 
    char(*)[!(has_const_iterator::value)] = 0) {
  std::cout << t;
}
 
template <typename T> void print_r(const T& v, 
    char(*)[has_const_iterator<T>::value] = 0) {
  std::cout << "[";
  typedef typename T::const_iterator iter_t;
  for(iter_t iter = v.begin(); iter != v.end(); iter++) {
        if(iter != v.begin()) std::cout << " ";
    print_r(*iter);
  }
  std::cout << "]";
}

Okay, this is longer, but much more flexible. Now we can use these function templates with pretty much any container type which has a const_iterator, even proxy or hand-made classes.
The only problem is that the char(*)[has_const_iterator::value] = 0 is quite bulky. This can be improved (but not shortened) by using enable_if from boost or the new(future) standard library.

You may want to follow me on twitter.

C++11 standard library threads with MinGW

When trying to compile a C++11-enable application under MinGW, I ran into a strange error.

bougabouga.cpp:42:1: error: 'mutex' in namespace 'std' does not name a type

What ? Did my fellow programmer, who gave me this code, made a typo ? Or forgot to #include some files ? Not at all. Let's consider this simple piece of code :

#include <mutex>
std::mutex mutex;


Well, isn't that something simple. But still, it won't compile, complaining about this missing std::mutex we just added to the namespace chain. So let's see what happens in this header file :

On line 50, we may have found our culprit :

#if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1)

This macro wraps the entire source file. So, do we have them ? The answer is yes, we have this stdint macro, but no, we don't have GNU threads. Simply because MinGW has no support for these. So instead of issuing an error, this header file happily discards all its content. This is unexpected behaviour, but it will be helpful when the time comes to make a workaround for that.

And this workaround is, as always, to rely on good ol' boost. Many classes of the standard thread library (If not all, but I did not have read the specs) can be easily replaced with the boost ones. So, a fix header file would look like that :

#include <boost/thread.hpp>

namespace std {
  using boost::mutex;
  using boost::recursive_mutex;
  using boost::lock_guard;
  using boost::condition_variable;
  using boost::unique_lock;
  using boost::thread;
}



Isn't that pretty ? You don't even have to change your code. Now you have several options : either you add it to a central header file (If you're the StdAfx.h type, you're lucky), or you add it either manually or with a script to your source files, or you modify your gcc header files (they are useless anyway). Keep in mind that you will still need to add the boost thread library at link time.

You may want to follow me on twitter.