ulrik@kaizer.se/
log

C++ constexpr foldr

This is a continuation of the "discoveries" of C++ constexpr from C++11, C++'s newest compile-time language.

You can perform simple computations over initializer lists at compile time, expressed as a general right fold. Neat, but is it useful?

#include <functional>
#include <initializer_list>
#include <iostream>

template <class T>
struct Summer : public std::binary_function<T,T,T> {
        constexpr T operator()(T x, T y) {
                return x + y;
        }
};

template <class T>
struct Minimizer : public std::binary_function<T,T,T> {
        constexpr T operator()(T x, T y) {
                return (x < y ? x : y);
        }
};

template <class T>
struct HasZero : public std::binary_function<T,bool,bool> {
        constexpr bool operator()(T x, bool y) {
                return y || (x == 0);
        }
};

template <class F,
         class X = typename F::first_argument_type,
         class Z = typename F::result_type>
constexpr Z foldr_(const X* xs, int off, int size, const Z& z) {
        return (off >= size ? z : F()(xs[off], foldr_<F,X,Z>(xs, off+1, size, z)));
}

/** Fold using a std::binary_function  F(X, Z) -> Z
 *  {a,b,c} -> F(a,F(b,F(c, Z))) -> Z
 */
template <class F,
         class X = typename F::first_argument_type,
         class Z = typename F::result_type>
constexpr Z foldr(const Z& z, const std::initializer_list<X>& xs) {
        return foldr_<F,X,Z>(xs.begin(), 0, xs.size(), z);
}

template <class T>
constexpr T sum(const std::initializer_list<T>& xs) {
        return foldr<Summer<T>>(0, xs);
}

int main(void) {
        std::cout << "Sum: " << foldr<Summer<double>>(0, {1,2,3}) << "\n";
        std::cout << "Contains Zero: " << foldr<HasZero<int>>(false, {1,2,0}) << "\n";
        std::cout << "Least value: " << foldr<Minimizer<double>>(1e9, {-1,-3,0}) << "\n";
        static_assert(foldr<Summer<double>>(0, {1,2,3}) == 6, "sum");
        static_assert(foldr<HasZero<int>>(false, {1,2,0}), "zero");
        static_assert(foldr<Minimizer<double>>(1e9, {-1,-3,0}) == -3, "min");
        static_assert(sum({1,2,3}) == 6, "Sum is not 6");
}

compile using GCC 4.6.1:

g++ -Wall -std=c++0x -o fold fold.cc

produces output:

Sum: 6
Contains Zero: 1
Least value: -3
Posted late Friday evening, October 21st, 2011
C++ constexpr

Here is some fun with C++11's constexpr. It seems we can check substring containment at compile time. The following example works fine with GCC 4.6.1.

#include <iostream>
#include <array>

constexpr bool not_end(const char *s, const int n) {
        return s && s[n];
}

/* does `s` have `t` as prefix. Use offsets ns, nt */
constexpr bool str_prefix(const char *s, const char *t, const int ns, const int nt) {
        return (s == t) || !*(t + nt) || (*(s + ns) == *(t + nt) && (str_prefix(s, t, ns+1, nt+1)));
}

constexpr int contains1(const char *s, const char *needle, const int n) {
        return not_end(s,n) && (str_prefix(s, needle, n, 0) || contains1(s, needle,n+1));
}

constexpr int contains(const char *s, const char *needle) {
        return contains1(s, needle, 0);
}

const int x = contains("froogler", "oogle");

int main(void) {
        std::array<int, 10 * contains("hi there", "the")> a;
        std::array<int, 10 * contains("hi thre", "the")> b;
        std::cout << "Array size for a is " << a.size() << "\n";
        std::cout << "Array size for b is " << b.size() << "\n";
        std::cout << "x: " << x << "\n";
}

It compiles without warnings using the commandline:

g++ -Wall -std=c++0x -o constarray constarray.cc

And produces the following output:

Array size for a is 10
Array size for b is 0
x: 1

So, is this a legal part of C++11? Is it a good thing? It is at least a more readable compile-time language than template metaprogramming.

If you want to contact me, I'm @englabenny on twitter

Edit to add a Bonus: an implementation of foldr over initializer lists, see C++ constexpr foldr

Posted Friday afternoon, October 21st, 2011 Tags:
Stealing icons

Are you wondering about the ascii icons?

Then you should look here

Great Artists Steal

Via a totally custom plugin you can tell Kupfer to use some icons from Quicksilver's repository. This is what it looks like: (qsicons branch on github.)

kupfer initial screen kupfer launching application kupfer blue box object
Posted late Sunday evening, April 3rd, 2011 Tags:

Sub-blogs:

View weblog archive