Building cURLpp 0.7.2

I want to use cURLpp for a project I've been working on, but there's no package for Ubuntu.

I downloaded the tarball, but discovered that example 18 would not compile. It would fail with the following error:


example18.cpp: In function ‘int main(int, char**)’:
example18.cpp:85: error: ‘BoostWriteFunction’ is not a member of ‘cURLpp::Options’
example18.cpp:85: error: ‘test’ was not declared in this scope
example18.cpp:85: error: expected type-specifier
example18.cpp:85: error: expected `;'
make[1]: *** [example18.o] Error 1

I discovered that usage of the Boost libraries was an option, and wasn't being tested for in example 18. boost::bind is one of the tools I frequently use in C++, the Boost support seems less optional to me, so I cleaned and ran configure --with-boost. Still, I got the error.

It became clear that the configure-generated config.h was not being included. This patch fixed that, and fixed the compile:


--- ../../curlpp-0.7.2-orig/curlpp/global.h     2007-09-22 09:31:10.000000000 -0500
+++ global.h    2009-04-05 10:57:58.000000000 -0500
@@ -26,6 +26,8 @@
 
 #ifndef HAVE_CONFIG_H
 #include "config.win32.h"
+#else
+#include "config.h"
 #endif
 
 #endif

Sun, 05 Apr 2009 11:02

Comments:

GCD Via C++ Template Metaprogramming

Via IRC:


    09:06 < jepler> michael: c++ template metaprogramming puzzle
    09:06 < jepler> I want a template class gcd<a,b> so that
        gcd<a,b>::value == gcd(a,b)
    09:07 < jepler> actually I bet it's pretty simple

It turns out Jeff's right; it's pretty simple.

#include <iostream>

template<int A, int B>
struct GCD { enum { value = GCD<B,A%B>::value }; };

template<int A> struct GCD<A,0> { enum { value = A }; };

int main() {
std::cout << GCD<N1,N2>::value << "\n";
return 0;
}

To run it, you compile it, defining N1 and N2 on the command line, and run the resulting program, which prints the result of the calculation GCD(N1,N2), which was performed at compile time. Neat!

~$ g++ -DN1=293888 -DN2=4837888 gcd.cc && ./a.out
512
~$

Sun, 20 Jul 2008 12:59

Comments:

Erasing Elements from a Map: A Mini-Pattern

It's a reality of programming in C++ that all containers are not created equal, and do not receive equal protection under the algorithms. Or something.

Today at work, for example, I needed to scan a std::map, and erase elements from it for which some predicate was true. The typical way to remove an element from a map is to use the map's erase method. There is an erase method that takes a range (a start and end iterator), but no way to perform the erase based on the result of a predicate. That is, there's no map::erase_if.

For sequence containers, there exists an algorithm, std::remove_if(start, end, pred), but it operates by reordering the elements of the range it's operating on, by assigning an element from one position to another with operator=. Because the first element of the pair that comprises a map::value_type, the key, is const, it can't be assigned to.

    
typedef std::map<T,U> Map;
typedef Map::value_type Value;
extern bool predicate(const Value &v);

Map m;

// Wrong: compile error.
std::remove_if(m.begin(), m.end(), std::ptr_fun(predicate)); 
    

The next obvious thing to try is an explicit loop, with an explicit branch based on the predicate. The naïve implementation, though, will have problems.

    
for(Map::iterator i = m.begin(); i != m.end(); i++) {
    if(predicate(*i))
        m.erase(i); // ONOZ!
}
    

ONOZ! because after the call to m.erase(i), i is no longer valid: it refers to memory that has been released. I suspect the increment clause of the for-statement puts us in nasal demon territory, but I'm not sure what the standard says.

To be honest, I knew the above constructs were wrong, but I didn't know if there was an idiom to get the behavior I wanted. After some research and some experimenting, the following is the construct I decided to use.

    
for(Map::iterator i = m.begin(); i != m.end(); /* increment in body */ ) {
    Map::iterator current = i++;
    if(predicate(*current))
        m.erase(current);
}
    

Thu, 21 Feb 2008 22:41

Comments:

ICU4C, FreeBSD 5.3, U_REGEX_MISMATCHED_PAREN: A Fix

I've come up with a fix for the U_REGEX_MISMATCHED_PAREN problem in ICU running on FreeBSD 5.3. I removed an entire type, and some casts to that type. I've tested on FreeBSD, Red Hat 9, and Ubuntu Dapper Drake, all passing the included tests with flying colors.

I haven't figured out why yet, but the cast of doOpenNonCaptureParen to EParseAction at i18n/regexcmp.cpp:345 was yielding 0. While digging in to this, I discovered that EParseAction was only used as the type for the single parameter to RegexCompile::doParseActions. (It's used in rbbiscan.cpp, too, but that's unrelated code, with a separate definition of the enum.) To reduce complexity, I tried passing a int32_t to doParseActions and stripping out the casts. That did the trick.

I assume that in 3.8, there will be a more comprehensive solution, but for now, this works.

The patches:

Mon, 11 Dec 2006 19:01

Comments: