Archive for category C++ Discoveries and Notes

python-like kwargs in C++

When dealing with functions that have lots of optional parameters, or at least for which resonable defaults are readily available, it’s often a bit of a frustration in C++. Generally defaults are specified during a function declaration as in:

double BinarySearch(std::function<double(double> fn,
                    int max_depth = 16, double epsilon = 1e-9,
                    double lower_bound = 0, double upper_bound = 100);

And then if we call BinarySearch with only one parameter then the call will use the default values for the rest. But what if I want to specify custom bound, and use the defaults for the other parameters? Admittedly, this is a somewhat contrived example since bounds are less likely to be optional then the others, and we could reorder them better going from most-likely-to-be-specified to least, but it’s easy to see how something more flexible would be desirable.

Consider then the following two code snippets. Which is more readable?

First snippet:

double solution = BinarySearch(fn, 0, 100);

Second snippet:

double solution = BinarySearch(fn, lower_bound = 0, upper_bound = 100);

I really like the way that optional arguments work in python with kwargs. I’d love to have that same kind of functionality in C++. kwargs.h implements one mechanism of achieving this.

How does it work

kwargs takes advantage of variadic templates in C++ to build up a single data structure which contains all of the optional parameters (I’ll call this a “parameter pack”). Each optional parameter of type T is stored in a structure of type Arg<tag,T> where tag is a unique numeric identifier associated with a particular optional argument key.

The parameter pack data structure derives from Arg<tag,T> for each (tag,T) pair that shows up in the list of optional arguments.

Overloading of the assignment (=) operator gives us an opportunity for building the (tag,T) pairs within the parameter list of the function call.

Get it

See the source and doxygen on github.

Example

I’ll conclude with an example usage:

#include <iostream>
#include "kwargs.h"
 
// these are tags which will uniquely identify the arguments in a parameter
// pack
enum Keys {
  c_tag,
  d_tag
};
 
// global symbols used as keys in list of kwargs
kw::Key<c_tag> c_key;
kw::Key<d_tag> d_key;
 
// a function taking kwargs parameter pack
template <typename... Args>
void foo(int a, int b, Args... kwargs) {
  // first, we construct the parameter pack from the parameter pack
  kw::ParamPack<Args...> params(kwargs...);
 
  std::cout << "foo:\n--------"
            << "\na: " << a
            << "\nb: " << b
  // We can attempt to retrieve a key while providing a default fallback value.
  // If c_key is in kwargs then this will return the value associated with
  // that key, and will have the correct type. Note that the type of the default
  // parameter in this case is const char*.
            << "\nc: " << kw::Get(params,c_key,"null");
  // We can also do stuff conditionally based on whether or not arg exists in
  // the param pack. We still need to provide a default value, since we need to
  // know the return type of the Get function when the key is not in kwargs.
  // In this case, the default value wont ever be used at runtime.
  if( kw::ContainsTag<c_tag,Args...>::result ) {
    std::cout << "\nd: " << kw::Get(params,d_key,0);
  }
 
  std::cout << "\n\n";
}
 
int main( int argc, char** argv )
{
  foo(1, 2);
  foo(1, 2, c_key=3);
  foo(1, 2, c_key=3, d_key=4);
  foo(1, 2, d_key=4);
}

No Comments

Range Based for-loops in C++11

One of the new features of C++11 that is a complete win in my opinion is the support for range-based for-loop syntax. Judicious use allows for significantly more compact and readable code. However, one thing that is lacking from this feature is the ability to iterate over a range of integers. This isn’t a problem, however, because it is very easy to implement.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// This file compiles as a single unit, you can test it by saving it 
// as range_for.cpp and compiling with 
// g++ -std=c++11 -o range_for range_for.cpp
// Adjust the interface as you see fit
 
// Implementation (put this in a header)
// ------------------------------------------------------------------
 
 
/// encapsulates a range of integral numbers for use in a c++11 range-based for 
/// loop
template< typename T>
struct Range
{
    /// the begin() and end() functions must return an iterator with a specific
    /// interface
    struct Iterator
    {
        T val;  ///< storage for the actual value
 
        /// implicit construction from the value type
        Iterator( T val ):val(val){}
 
        /// the range-based for loops attempt to dereference an iterator using
        /// this operator
        T operator*(){ return val; }
 
        /// the range-based for loops quit when the comparison of iter != end
        /// returns false
        bool operator !=( T other ){ return val != other; }
 
        /// iterators in a range-based for loop must have the prefix increment
        /// operator
        Iterator& operator++(){ ++val; return *this; }
 
        /// we likely want to implicitly convert to the value type
        operator T(){ return val; }
    };
 
    private:
        T m_begin;  ///< the first integral value
        T m_end;    ///< one past the last integral value
 
    public:
        /// construct a range [begin, end)
        Range( T begin, T end ):
            m_begin(begin),
            m_end(end)
        {}
 
        /// interface required by range-based for loop
        Iterator begin(){ return m_begin; }
 
        /// interface required by range-based for loop
        Iterator end()  { return m_end;   }
};
 
 
/// return an object which can be used in a range-based for loop
template <typename T>
Range<T> range( T begin, T end )
{
    return Range<T>(begin,end);
}
 
 
 
 
// Usage 
// -------------------------------------------------------------------
 
#include <iostream>
 
int main(int argc, char** argv)
{
    std::cout << "Static ranges\n----------------\n";
    std::cout << "\nint:\n";
    for( int i : range(1,5) )
        std::cout << "   i: " << i << "\n";
 
    std::cout << "\nunsigned int:\n";
    for( unsigned int i : range(1u,5u) )
        std::cout << "   i: " << i << "\n";
 
    std::cout << "\nlong:\n";
    for( long i : range(1L,5L) )
        std::cout << "   i: " << i << "\n";
 
    std::cout << "\nDynamic range (program args)\n----------------\n";
    for( int i : range(0,argc) )
        std::cout << i << " : " << argv[i] << "\n";
 
    return 0;
}

The range<T>( T begin, T end ) function template returns a Range<T> object which supports the required interface for range-based loops. It has a begin and end method, both of which return an iterator. The iterator has the same storage says as the integral type used to instantiate the templates. It is implicitly convertable to and from the integral type. Futhermore, it has the prefix ++ operator, and can be “dereferenced” to get the stored integral value.

The implementation is likely to yield compiled code equivalent to a normal for loop.

The output of the demo program above is:

josh@Nadie:~/Desktop$ g++ -std=c++11 -o range_for range_for.cpp 
josh@Nadie:~/Desktop$ ./range_for arg1 arg2 arg3 arg4 arg5
Static ranges
----------------

int:
   i: 1
   i: 2
   i: 3
   i: 4

unsigned int:
   i: 1
   i: 2
   i: 3
   i: 4

long:
   i: 1
   i: 2
   i: 3
   i: 4

Dynamic range (program args)
----------------
0 : ./range_for
1 : arg1
2 : arg2
3 : arg3
4 : arg4
5 : arg5
josh@Nadie:~/Desktop$ 

No Comments

C++ FreeFontStack

I’ve been doing a lot of research into free software font technologies and as a consequence I’ve been playing around a lot with Freetype2 and Fontconfig (actually the library interface libfontconfig). These are “straight up” c-libraries and so I (personally) find the interface a bit “clunky” in C++ code. Don’t get me wrong, I wouldn’t presume to criticize their design as it is clear the authors/maintainers are far more knowledgeable about this stuff than I am… but from a users perspective I desire a bit more.

So… I’ve written some C++ wrappers for freetype2 and fontconfig. The main goals in these projects are:

  • Don’t change the usage patterns of the library
  • Provide a pointer-like type which automatically performs reference counting for reference counted objects
  • Provide a pointer-like type which exposes member-functions where relevant
  • Provide a pointer-like type which still allows access to the public data members of the underlying structures
  • Allow access to the native c-pointer for use in parts of the library that I haven’t finished wrapping

So far… cppfontconfig wraps more or less all the functionality of libfontconfig. I’d still like to add some interface for assignment by touples in order to grab error codes when desired without the error being part of the function signature. Perhaps in the future.

cppfreetype isn’t nearly as complete (freetype2 is a much larger library). I still haven’t decided the appropriate way to deal with structures which are normally stack allocated. I do however have wrappers for FT_Face, FT_GlyphSlot, and an iterface for iterating over contours and points in an FT_Outline.

These libraries are released as GPLv3. I have public git repositories and publicly accessible doxygen documentation available in the links below. No bug tracker though since I’m giving up on redmine.

library source repository documentation
cppfreetype git://git.cheshirekow.com/cppfreetype.git www.cheshirekow.com/~projects/cppfreetype
cppfontconfig git://git.cheshirekow.com/cppfontconfig.git www.cheshirekow.com/~projects/cppfontconfig

No Comments