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