Alex Reinking
Alex Reinking

Reputation: 19866

Haskell-like `const` in C++

So in the past few weeks, I've been experimenting with functional-programming type solutions to problems in C++11, and from time to time, I've been in a situation where I need a function that returns a constant value.

In Haskell, there is a function

const :: a -> b -> a
const x = \_ -> x

that returns a function that evaluates to const's original argument, no matter what argument is supplied to it. I would like to create something similar in C++11. Such constructions are useful for signifying special behavior in functions (a constant function of true sent to a filter would leave the data intact). Here's my first attempt:

template<class T>
std::function<T(...)> constF(T x) {
    return ([x](...) { return x; });
}

This compiles on its own, but any attempt to use it results in incomplete-type errors. My second attempt was this:

template<class T, class... Args>
std::function<T(Args...)> constF(T x) {
    return ([x](Args...) { return x; });
}

This comes closer, but doesn't allow me to supply any arguments, unless I explicitly state them.

auto trueFunc1 = constF(true);
auto trueFunc2 = constF<bool, int>(true);
cout << trueFunc1() << endl; //works
cout << trueFunc1(12) << endl; //doesn't compile
cout << trueFunc2(12) << endl; //works

Ideally, a correct construction would produce no difference between trueFunc1 and trueFunc2.

Is this even possible in C++?

Upvotes: 3

Views: 190

Answers (1)

Casey
Casey

Reputation: 42554

Since C++11 doesn't have generic or variadic lambdas, I'd write a functor template class:

template <typename T>
// requires CopyConstructible<T>
class const_function {
  T value;
public:
  template <typename U, typename = typename std::enable_if<std::is_convertible<U,T>::value>::type>
  const_function(U&& val) :
    value(std::forward<U>(val)) {}

  template <typename... Args>
  T operator () (Args&&...) const {
    return value;
  }
};

and a nice type-deducing wrapper to make them:

template <typename T>
const_function<typename std::remove_reference<T>::type>
constF(T&& t) {
  return {std::forward<T>(t)};
}

In C++1y, I think the simple equivalent is:

template <typename T>
auto constF(T&& t) {
  return [t{std::forward<T>(t)}](auto&&...){return t;};
}

Upvotes: 5

Related Questions