Reputation: 19866
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
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