I am playing around with trying to implement the numeric literal operator template.
#include <string_view>
#include <cstdint>
#include <cmath>
#include <iostream>
#include <boost/mp11/integer_sequence.hpp>
#include <boost/mp11/algorithm.hpp>
using namespace boost::mp11;
template <char... Cs>
[[nodiscard]] constexpr auto operator""_c(){
int weight =std::pow(10, sizeof... (Cs));
// unused, would like to transform it using lambda that mutably captures
// weight
using ints = index_sequence<sizeof... (Cs)>;
// ugly fold way
auto val = ((weight/=10,(int)(Cs-'0')*weight) + ...);
return val;
}
int main(){
std::cout << 0_c << std::endl;
std::cout << 00_c << std::endl;
std::cout << 01_c << std::endl;
std::cout << 123_c << std::endl;
}
This code works for simple cases(correctness is not important, e.g. negative numbers), it is just an example, but code looks ugly and clang emits a warning for modifying weight multiple times, so I guess code is buggy(undefined or unspecified behavior) although it seems to work...
Now I wonder is there a way for me to transform the ints I use(it is from boost::mp11, but same thing exists in std::) with a stateful lambda (that modifies weight).
So I would like to transfer ints, that are <0,1,2> into something like <100,10,1>
I presume this has been asked before but this is very hard to search for.
To be clear: operator "" is just a toy problem, my real question is about mapping the values of integer sequence with a stateful lambda.
Also if not clear from question: I am perfectly happy to use boost mp11, but could not find anything in the docs.
So I would like to transfer ints, that are <0,1,2> into something like
<100,10,1>
First, you can convert std::index_sequence to std::array, then perform your operations on it as you normally do, and finally, convert std::array to std::index_sequence again.
In order for the stateful lambda to work at compile-time, we can accept a function that can return the stateful lambda then get it internally:
template<std::size_t... Is>
constexpr auto transform_seq(std::index_sequence<Is...>, auto get_op) {
// index_sequence -> array
constexpr auto arr = [op = get_op()]() mutable {
std::array<std::size_t, sizeof...(Is)> arr{Is...};
for (auto& value : arr)
value = op(value);
return arr;
}();
// array -> index_sequence
constexpr auto seq = [&]<std::size_t... Js>(std::index_sequence<Js...>) {
return std::index_sequence<std::get<Js>(arr)...>{};
}(std::make_index_sequence<arr.size()>{});
return seq;
};
Then you can perform the index_sequence conversion according to op you pass in:
using input1 = std::index_sequence<0,1,2>;
auto gen_op1 = [] {
return [w = 1000](auto x) mutable { w /= 10; return w; };
};
using res1 = decltype(transform_seq(input1{}, gen_op1));
static_assert(std::same_as<res1, std::index_sequence<100, 10, 1>>);
using input2 = std::index_sequence<0,1,2,3>;
auto gen_op2 = [] {
return [b = true] (auto x) mutable { b = !b; return b * 10 + x; };
};
using res2 = decltype(transform_seq(input2{}, gen_op2));
static_assert(std::same_as<res2, std::index_sequence<0,11,2,13>>);
Demo.
I think you want:
template <typename F, std::size_t ... Is>
constexpr auto apply(F f, std::index_sequence<Is...>)
-> std::index_sequence<f(Is)...>
{
return {};
}
template <char... Cs>
[[nodiscard]] constexpr auto operator""_c(){
return []<std::size_t ... Pows>(std::index_sequence<Pows...>){
return ((Pows * (Cs - '0')) + ...);
}(apply([](std::size_t n){ return ipow(10, sizeof...(Cs) - n - 1);},
std::make_index_sequence<sizeof...(Cs)>()));
}
Demo
But doing computation directly seems even simpler:
template <char... Cs>
[[nodiscard]] constexpr auto operator""_c(){
constexpr auto res =
[]<std::size_t ... Is>(std::index_sequence<Is...>){
return ((ipow(10, sizeof...(Cs) - Is - 1) * (Cs - '0')) + ...);
}(std::make_index_sequence<sizeof...(Cs)>());
return res;
}
I want to use std::any in my program but I find myself writing a lot of conditional statements like this:
if (anything.type() == typeid(short)) {
auto s = std::any_cast<short>(anything);
} else if (anything.type() == typeid(int)) {
auto i = std::any_cast<int>(anything);
} else if (anything.type() == typeid(long)) {
auto l = std::any_cast<long>(anything);
} else if (anything.type() == typeid(double)) {
auto d = std::any_cast<double>(anything);
} else if (anything.type() == typeid(bool)) {
auto b = std::any_cast<bool>(anything);
}
Note that I omitted much of the else if conditions for brevity.
My program can use any of the defined types that can be stored in std::any so these if-then statements are quite long. Is there a way to refactor the code so that I can write it once?
My original inclination was to use templates like so:
template<typename T>
T AnyCastFunction(std::any) {
T type;
if (anything.type() == typeid(short)) {
type = std::any_cast<short>(anything);
} else if (anything.type() == typeid(int)) {
type = std::any_cast<int>(anything);
} else if (anything.type() == typeid(long)) {
type = std::any_cast<long>(anything);
} else if (anything.type() == typeid(double)) {
type = std::any_cast<double>(anything);
} else if (anything.type() == typeid(bool)) {
type = std::any_cast<bool>(anything);
}
return type;
}
However, this leads to "couldn't deduce template parameter T" errors. How can I refactor this to avoid writing the large if/else blocks many times throughout the program?
If you have a known, fixed list of possible types, don't use std::any. Use std::variant<Ts...>. That makes Dietmar's answer look like this:
#include <variant>
void test(std::variant<int, double, char const*> v)
{
std::visit([](auto value){ std::cout << "value=" << value << "\n"; }, v);
}
which is the same thing, except (a) you don't have to implement visit yourself (b) this is massively more efficient at runtime and (c) this is type safe - you can't forget to check a particular type! Really even if you don't care about (a) or (b), (c) is a huge win.
And if you don't have a known, fixed list of possible types - which is the typical use-case for wanting std::any - then anything you're doing with std::any doesn't make sense anyway. You can't enumerate all possible copyable types (there are an infinite amount of them), so you can't necessarily retrieve the contents. So I really think variant is what you want.
Well, if you're sure you need such a broad range stored in any...
template<typename T> void visit(T &&t) { std::cout << "Hi " << t << "!\n"; }
void try_visit(std::any &&) { std::cout << "Unknown type\n"; }
template<typename T, typename... Ts> void try_visit(std::any thing) {
if(thing.type() == typeid(T)) {
visit(std::any_cast<T>(thing));
return;
}
if constexpr(sizeof...(Ts) > 0) try_visit<Ts...>(std::move(thing));
else try_visit(std::move(thing));
}
int main() {
try_visit<short, int, double, bool, long>(std::any{42});
}
%-}
I find this type of code fun to write.
any_visitor<types...> is a function object that visits a set of types.
You invoke it with an any followed by a function object. It then invokes the function object with whichever of the types... is in the any.
So you do any_vistor<int, double>{}( something, [](auto&& x) { /* some code */ } ).
If none of the types... are in the any, it invokes the function object with a std::any for you to deal with the extra case.
We can also write a variant that instead of passing the std::any to the functor, throws or returns false or something.
template<class...Ts>
struct any_visitor;
template<>
struct any_visitor<> {
template<class F>
decltype(auto) operator()( std::any& a, F&& f ) const {
return std::forward<F>(f)(a);
}
};
template<class...Ts>
struct any_visitor {
private:
struct accum {
std::size_t x = 0;
friend accum operator+( accum lhs, accum rhs ) {
if (lhs.x || rhs.x) return {lhs.x+1};
else return {};
}
};
public:
template<class Any, class F>
void operator()(Any&& any, F&& f) const {
// sizeof...(Ts) none in the list
// otherwise, index of which any is in the list
std::size_t which = sizeof...(Ts) - (accum{} + ... + accum{ any.type() == typeid(Ts) }).x;
using table_entry = void(*)(Any&&, F&&);
static const table_entry table[] = {
+[](Any&& any, F&& f) {
std::forward<F>(f)( std::any_cast<Ts>( std::forward<Any>(any) ) );
}...,
+[](Any&& any, F&& f) {
std::forward<F>(f)( std::forward<Any>(any) );
}
};
table[which]( std::forward<Any>(any), std::forward<F>(f) );
}
};
template<class...Fs>
struct overloaded:Fs... {
using Fs::operator()...;
};
template<class...Fs>
overloaded(Fs&&...)->overloaded<std::decay_t<Fs>...>;
I also included overloaded which makes it easier to dispatch. If you want to handle all types uniformly, except handle an error case, you can do:
overloaded{
[](auto const& x){ std::cout << x << "\n"; },
[](std::any const&){ std::cout << "Unknown type\n"; }
}
and pass that as the function object to any_visitor.
Here is some test code:
std::any foo=7;
std::any bar=3.14;
auto visitor = overloaded{
[](int x){std::cout << x << "\n";},
[](auto&&){std::cout << "Unknown\n";}
};
any_visitor<int>{}( foo, visitor );
any_visitor<int>{}( bar, visitor );
which outputs:
7
Unknown
Live example.
Implementation wise, this code uses a dispatch table (sort of like a vtable) to map the index of the type stored in the any to which overload of the function object we invoke.
Yet another approach would be to write:
template<class...Ts>
std::optional<std::variant<Ts...>> to_variant( std::any );
which converts a std::any to a variant if its types match. Then use the usual visiting machinery on std::variant instead of rolling your own.
The basic idea is to create an std::any visitor and do the necessary processing in a function called from the visitor. That basic principle is straight forward. Let's start with supporting just one type:
#include <any>
#include <iostream>
#include <type_traits>
template <typename T, typename Any, typename Visitor>
auto any_visit1(Any&& any, Visitor visit)
-> std::enable_if_t<std::is_same_v<std::any, std::decay_t<Any>>>
{
if (any.type() == typeid(T)) {
visit(std::any_cast<T>(std::forward<Any>(any)));
}
}
int main() {
std::any a0(17);
any_visit1<int>(a0, [](auto value){ std::cout << "value=" << value << "\n"; });
}
The next step is to remove the one type restriction. As the explicit template parameters come first and are an open-ended list and the function object should be a deduced template parameter, you can't quite use a function template. However, a variable template (with an inline constexpr, of course, hence variable...) does the trick:
#include <any>
#include <iostream>
#include <type_traits>
template <typename... T>
inline constexpr auto any_visit =
[](auto&& any, auto visit) -> std::enable_if_t<std::is_same_v<std::any, std::decay_t<decltype(any)>>> {
(
(any.type() == typeid(T) && (visit(std::any_cast<T>(std::forward<decltype(any)>(any))), true))
|| ...)
// Uncomment the line below to have visit(any) called for unhandled types
// || (visit(std::forward<decltype(any)>(any)), true)
;
};
void test(std::any any)
{
any_visit<int, double, char const*>(any, [](auto value){ std::cout << "value=" << value << "\n"; });
}
int main() {
test(17);
test(3.14);
test(+"foo");
}
If you need multiple std::any objects decoded you'd just pass suitable [lambda?] functions into it which refer to the other objects and keep building up the object until you got all the ones you need.
I have a class with operator() like this:
struct S
{
int operator()(int a, int b, int c, int d);
};
Example usage:
S s;
int i = s(1, 2, 3, 4);
I need my users to be able to use an alternate syntax:
int i = s[1][2][3][4]; // equivalent to calling s(1, 2, 3, 4)
I know I need to add S::operator[](int a) and that it needs to return a helper object. But beyond that it all gets a bit complex and I have a feeling that I am reinventing the wheel since other libraries (e.g. multidimensional arrays) probably already offer similar interface.
Ideally I'd just use an existing library to achieve this goal. Failing that, how can I achieve my goal with the most generic code?
Edit: ideally I'd like to achieve this without any runtime penalty on a modern optimizing compiler.
Here we go!
First of all, the code is kind of messy- I have to accumulate the argument values as we go, and the only way I could think of (at least in C++03) is to pass the immediate indices set around as arrays.
I have checked this on G++ 4.5.1 (Windows / MinGW) and I confirm that on -O3 the call:
s[1][2][3][4];
yields the same assembler code as:
s(1,2,3,4);
So - no runtime overhead if your compiler is smart with optimisations. Good job, GCC team!
Here goes the code:
#include <iostream>
template<typename T, unsigned N, unsigned Count>
struct PartialResult
{
static const int IndicesRemembered = Count-1-N;
T& t;
int args[IndicesRemembered];
PartialResult(T& t, int arg, const int* rest) : t(t) {
for (int i=0; i<IndicesRemembered-1; ++i) {
args[i] = rest[i];
}
if (IndicesRemembered>0) args[IndicesRemembered-1] = arg;
}
PartialResult<T, N-1, Count> operator[](int k) {
return PartialResult<T, N-1, Count>(t, k, args);
}
};
template<typename T, unsigned Count>
struct PartialResult<T, 0, Count>
{
static const int IndicesRemembered = Count-1;
T& t;
int args[IndicesRemembered];
PartialResult(T& t, int arg, const int* rest) : t(t) {
for (int i=0; i<IndicesRemembered-1; ++i) {
args[i] = rest[i];
}
if (IndicesRemembered>0) args[IndicesRemembered-1] = arg;
}
void operator[](int k) {
int args2[Count];
for (int i=0; i<Count-1; ++i) {
args2[i] = args[i];
}
args2[Count-1] = k;
t(args2);
}
};
template<typename T, unsigned Count>
struct InitialPartialResult : public PartialResult<T, Count-2, Count> {
InitialPartialResult(T& t, int arg)
: PartialResult<T, Count-2, Count>(t, arg, 0) {}
};
struct C {
void operator()(const int (&args)[4]) {
return operator()(args[0], args[1], args[2], args[3]);
}
void operator()(int a, int b, int c, int d) {
std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
InitialPartialResult<C, 4> operator[](int m) {
return InitialPartialResult<C, 4>(*this, m);
}
};
And seriously, please, don't use this and just stick with operator(). :) Cheers!
This is an attempt at the bind approach. I doubt that it's particularly efficient, and it has some nasty bits in it, but I post it in case anyone knows how to fix it. Please edit:
template <int N>
struct Helper {
function_type<N>::type f;
explicit Helper(function_type<N>::type f) : f(f) {}
Helper<N-1> operator[](int p) {
return Helper<N-1>(bound<N-1>(f,p));
}
};
template<>
struct Helper<0> {
function_type<0>::type f;
explicit Helper(function_type<0>::type f) : f(f) {}
operator int() {
return f();
}
};
Helper<3> S::operator[](int p) {
return Helper<3>(std::bind(s, _1, _2, _3));
}
where s is an expression that returns operator() bound to this. Something along the lines of std::bind(std::mem_fun(S::operator(), this, _1, _2, _3, _4)). Although I can't remember whether std::bind can already handle member functions, mem_fun might not be needed.
function_type<N>::type is std::function<int, [int, ... n times]>, and bound<N> is function_type<N>::type bound(function_type<N+1>::type f, int p) { return std::bind(f, p, _1, _2, ... _N); }. I'm not immediately sure how to define those recursively, but you could just list them up to some limit.
I would avoid this altogether and offer just operator(), but if you really want to give it a shot, the idea is that your type's operator[] would return an object of a helper type that holds both a reference to your object and the value that was passed in. That helper class will implement operator[] by again storing a reference to the original object and the arguments to both calls to []. This would have to be done for all but the last level (I.e. a fair amount of helpers). I the last level, operator[] will take its argument together with all previously stored values and call operator() with all of the previously stored values plus the current value.
A common way of phrasing this is saying that each intermetiate type binds one of the arguments of the call to operator(), with the last one executing the call with all bound arguments.
Depending on whether you want to support more or less number of dimensions of arrays you might want/need to complicate this even more to make it generic. In general it is not worth the effort and just offering operator() is usually the solution. Remember that it is better to keep things as simple as possible: less effort to write and much less effort to maintain.
Here is a Fusion implementation that supports arbitrary parameter and return types. Kudos to anyone that can get this working (please let me know if you do)!
template <class Derived, class ReturnValue, class Sequence>
struct Bracketeer
{
typedef ReturnValue result_type;
typedef boost::fusion::result_of::size<Sequence> Size;
struct RvBase
{
Sequence sequence;
Derived *derived;
};
template <int n>
struct Rv : RvBase
{
Rv(Derived *d) { this->derived = d; }
Rv(RvBase *p) : RvBase(*p) { }
Rv<n-1> operator[](typename boost::fusion::result_of::at_c<Sequence const, n-1>::type v)
{
boost::fusion::at_c<Size::value - 1 - n>(sequence) = v;
return Rv<n-1>(this);
}
};
template <>
struct Rv<0> : RvBase
{
Rv(Derived *d) { this->derived = d; }
Rv(RvBase *p) : RvBase(*p) { }
ReturnValue operator[](typename boost::fusion::result_of::at_c<Sequence, Size::value - 1>::type v)
{
boost::fusion::at_c<Size::value - 1>(sequence) = v;
return invoke(*derived, sequence);
}
};
Rv<Size::value - 1> operator[](typename boost::fusion::result_of::at_c<Sequence, 0>::type v)
{
Rv<Size::value> rv(static_cast<Derived*>(this));
return rv[v];
}
};
struct S
:
Bracketeer<S, int, boost::fusion::vector<int, int, int, int> >
{
int operator()(int a, int b, int c, int d);
};
I am new to C++11. I am writing the following recursive lambda function, but it doesn't compile.
sum.cpp
#include <iostream>
#include <functional>
auto term = [](int a)->int {
return a*a;
};
auto next = [](int a)->int {
return ++a;
};
auto sum = [term,next,&sum](int a, int b)mutable ->int {
if(a>b)
return 0;
else
return term(a) + sum(next(a),b);
};
int main(){
std::cout<<sum(1,10)<<std::endl;
return 0;
}
compilation error:
vimal#linux-718q:~/Study/09C++/c++0x/lambda> g++ -std=c++0x sum.cpp
sum.cpp: In lambda function:
sum.cpp:18:36: error: ‘((<lambda(int, int)>*)this)-><lambda(int, int)>::sum’ cannot be used as a function
gcc version
gcc version 4.5.0 20091231 (experimental) (GCC)
But if I change the declaration of sum() as below, it works:
std::function<int(int,int)> sum = [term,next,&sum](int a, int b)->int {
if(a>b)
return 0;
else
return term(a) + sum(next(a),b);
};
Could someone please throw light on this?
Think about the difference between the auto version and the fully specified type version. The auto keyword infers its type from whatever it's initialized with, but what you're initializing it with needs to know what its type is (in this case, the lambda closure needs to know the types it's capturing). Something of a chicken-and-egg problem.
On the other hand, a fully specified function object's type doesn't need to "know" anything about what is being assigned to it, and so the lambda's closure can likewise be fully informed about the types its capturing.
Consider this slight modification of your code and it may make more sense:
std::function<int(int, int)> sum;
sum = [term, next, &sum](int a, int b) -> int {
if (a > b)
return 0;
else
return term(a) + sum(next(a), b);
};
Obviously, this wouldn't work with auto. Recursive lambda functions work perfectly well (at least they do in MSVC, where I have experience with them), it's just that they aren't really compatible with type inference.
The trick is to feed in the lambda implementation to itself as a parameter, not by capture.
const auto sum = [term, next](int a, int b) {
auto sum_impl = [term, next](int a, int b, auto& sum_ref) mutable {
if (a > b) {
return 0;
}
return term(a) + sum_ref(next(a), b, sum_ref);
};
return sum_impl(a, b, sum_impl);
};
All problems in computer science can be solved by another level of indirection. I first found this easy trick at http://pedromelendez.com/blog/2015/07/16/recursive-lambdas-in-c14/
It does require C++14 while the question is on C++11, but perhaps interesting to most.
Here's the full example at Godbolt.
Going via std::function is also possible but can result in slower code. But not always. Have a look at the answers to std::function vs template
This is not just a peculiarity about C++,
it's directly mapping to the mathematics of lambda calculus. From Wikipedia:
Lambda calculus cannot express this as directly as some other
notations:
all functions are anonymous in lambda calculus, so we can't refer to a
value which is yet to be defined, inside the lambda term defining that
same value. However, recursion can still be achieved by arranging for a
lambda expression to receive itself as its argument value
With C++14, it is now quite easy to make an efficient recursive lambda without having to incur the additional overhead of std::function, in just a few lines of code:
template <class F>
struct y_combinator {
F f; // the lambda will be stored here
// a forwarding operator():
template <class... Args>
decltype(auto) operator()(Args&&... args) const {
// we pass ourselves to f, then the arguments.
return f(*this, std::forward<Args>(args)...);
}
};
// helper function that deduces the type of the lambda:
template <class F>
y_combinator<std::decay_t<F>> make_y_combinator(F&& f) {
return {std::forward<F>(f)};
}
with which your original sum attempt becomes:
auto sum = make_y_combinator([term,next](auto sum, int a, int b) -> int {
if (a>b) {
return 0;
}
else {
return term(a) + sum(next(a),b);
}
});
In C++17, with CTAD, we can add a deduction guide:
template <class F> y_combinator(F) -> y_combinator<F>;
Which obviates the need for the helper function. We can just write y_combinator{[](auto self, ...){...}} directly.
In C++20, with CTAD for aggregates, the deduction guide won't be necessary.
In C++23, with deducing this, you don't need a Y-combinator at all:
auto sum = [term,next](this auto const& sum, int a, int b) -> int {
if (a>b) {
return 0;
}
else {
return term(a) + sum(next(a),b);
}
}
I have another solution, but work only with stateless lambdas:
void f()
{
static int (*self)(int) = [](int i)->int { return i>0 ? self(i-1)*i : 1; };
std::cout<<self(10);
}
Trick here is that lambdas can access static variables and you can convert stateless ones to function pointer.
You can use it with standard lambdas:
void g()
{
int sum;
auto rec = [&sum](int i) -> int
{
static int (*inner)(int&, int) = [](int& _sum, int i)->int
{
_sum += i;
return i>0 ? inner(_sum, i-1)*i : 1;
};
return inner(sum, i);
};
}
Its work in GCC 4.7
To make lambda recursive without using external classes and functions (like std::function or fixed-point combinator) one can use the following construction in C++14 (live example):
#include <utility>
#include <list>
#include <memory>
#include <iostream>
int main()
{
struct tree
{
int payload;
std::list< tree > children = {}; // std::list of incomplete type is allowed
};
std::size_t indent = 0;
// indication of result type here is essential
const auto print = [&] (const auto & self, const tree & node) -> void
{
std::cout << std::string(indent, ' ') << node.payload << '\n';
++indent;
for (const tree & t : node.children) {
self(self, t);
}
--indent;
};
print(print, {1, {{2, {{8}}}, {3, {{5, {{7}}}, {6}}}, {4}}});
}
prints:
1
2
8
3
5
7
6
4
Note, result type of lambda should be specified explicitly.
You can make a lambda function call itself recursively. The only thing you need to do is to is to reference it through a function wrapper so that the compiler knows it's return and argument type (you can't capture a variable -- the lambda itself -- that hasn't been defined yet).
function<int (int)> f;
f = [&f](int x) {
if (x == 0) return 0;
return x + f(x-1);
};
printf("%d\n", f(10));
Be very careful not to run out of the scope of the wrapper f.
I ran a benchmark comparing a recursive function vs a recursive lambda function using the std::function<> capture method. With full optimizations enabled on clang version 4.1, the lambda version ran significantly slower.
#include <iostream>
#include <functional>
#include <chrono>
uint64_t sum1(int n) {
return (n <= 1) ? 1 : n + sum1(n - 1);
}
std::function<uint64_t(int)> sum2 = [&] (int n) {
return (n <= 1) ? 1 : n + sum2(n - 1);
};
auto const ITERATIONS = 10000;
auto const DEPTH = 100000;
template <class Func, class Input>
void benchmark(Func&& func, Input&& input) {
auto t1 = std::chrono::high_resolution_clock::now();
for (auto i = 0; i != ITERATIONS; ++i) {
func(input);
}
auto t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count();
std::cout << "Duration: " << duration << std::endl;
}
int main() {
benchmark(sum1, DEPTH);
benchmark(sum2, DEPTH);
}
Produces results:
Duration: 0 // regular function
Duration: 4027 // lambda function
(Note: I also confirmed with a version that took the inputs from cin, so as to eliminate compile time evaluation)
Clang also produces a compiler warning:
main.cc:10:29: warning: variable 'sum2' is uninitialized when used within its own initialization [-Wuninitialized]
Which is expected, and safe, but should be noted.
It's great to have a solution in our toolbelts, but I think the language will need a better way to handle this case if performance is to be comparable to current methods.
Note:
As a commenter pointed out, it seems latest version of VC++ has found a way to optimize this to the point of equal performance. Maybe we don't need a better way to handle this, after all (except for syntactic sugar).
Also, as some other SO posts have outlined in recent weeks, the performance of std::function<> itself may be the cause of slowdown vs calling function directly, at least when the lambda capture is too large to fit into some library-optimized space std::function uses for small-functors (I guess kinda like the various short string optimizations?).
Here is a refined version of the Y-combinator solution based on one proposed by #Barry.
template <class F>
struct recursive {
F f;
template <class... Ts>
decltype(auto) operator()(Ts&&... ts) const { return f(std::ref(*this), std::forward<Ts>(ts)...); }
template <class... Ts>
decltype(auto) operator()(Ts&&... ts) { return f(std::ref(*this), std::forward<Ts>(ts)...); }
};
template <class F> recursive(F) -> recursive<F>;
auto const rec = [](auto f){ return recursive{std::move(f)}; };
To use this, one could do the following
auto fib = rec([&](auto&& fib, int i) {
// implementation detail omitted.
});
It is similar to the let rec keyword in OCaml, although not the same.
In C++23 deducing this (P0847) will be added:
auto f = [](this auto& self, int i) -> int
{
return i > 0 ? self(i - 1) + i : 0;
}
For now its only available in EDG eccp and (partially) available in MSVC:
https://godbolt.org/z/f3E3xT3fY
This is a slightly simpler implementation of the fixpoint operator which makes it a little more obvious exactly what's going on.
#include <iostream>
#include <functional>
using namespace std;
template<typename T, typename... Args>
struct fixpoint
{
typedef function<T(Args...)> effective_type;
typedef function<T(const effective_type&, Args...)> function_type;
function_type f_nonr;
T operator()(Args... args) const
{
return f_nonr(*this, args...);
}
fixpoint(const function_type& p_f)
: f_nonr(p_f)
{
}
};
int main()
{
auto fib_nonr = [](const function<int(int)>& f, int n) -> int
{
return n < 2 ? n : f(n-1) + f(n-2);
};
auto fib = fixpoint<int,int>(fib_nonr);
for (int i = 0; i < 6; ++i)
{
cout << fib(i) << '\n';
}
}
C++ 14:
Here is a recursive anonymous stateless/no capture generic set of lambdas
that outputs all numbers from 1, 20
([](auto f, auto n, auto m) {
f(f, n, m);
})(
[](auto f, auto n, auto m) -> void
{
cout << typeid(n).name() << el;
cout << n << el;
if (n<m)
f(f, ++n, m);
},
1, 20);
If I understand correctly this is using the Y-combinator solution
And here is the sum(n, m) version
auto sum = [](auto n, auto m) {
return ([](auto f, auto n, auto m) {
int res = f(f, n, m);
return res;
})(
[](auto f, auto n, auto m) -> int
{
if (n > m)
return 0;
else {
int sum = n + f(f, n + 1, m);
return sum;
}
},
n, m); };
auto result = sum(1, 10); //result == 55
Here's the proof that a recursive lambda with a small body almost has the same performance like a usual recursive fuction which can call itself directly.
#include <iostream>
#include <chrono>
#include <type_traits>
#include <functional>
#include <atomic>
#include <cmath>
using namespace std;
using namespace chrono;
unsigned recursiveFn( unsigned x )
{
if( x ) [[likely]]
return recursiveFn( x - 1 ) + recursiveFn( x - 1 );
else
return 0;
};
atomic_uint result;
int main()
{
auto perf = []( function<void ()> fn ) -> double
{
using dur_t = high_resolution_clock::duration;
using urep_t = make_unsigned_t<dur_t::rep>;
high_resolution_clock::duration durMin( (urep_t)-1 >> 1 );
for( unsigned r = 10; r--; )
{
auto start = high_resolution_clock::now();
fn();
dur_t dur = high_resolution_clock::now() - start;
if( dur < durMin )
durMin = dur;
}
return durMin.count() / 1.0e9;
};
auto recursiveLamdba = []( auto &self, unsigned x ) -> unsigned
{
if( x ) [[likely]]
return self( self, x - 1 ) + self( self, x - 1 );
else
return 0;
};
constexpr unsigned DEPTH = 28;
double
tLambda = perf( [&]() { ::result = recursiveLamdba( recursiveLamdba, DEPTH ); } ),
tFn = perf( [&]() { ::result = recursiveFn( DEPTH ); } );
cout << trunc( 1000.0 * (tLambda / tFn - 1.0) + 0.5 ) / 10.0 << "%" << endl;
}
For my AMD Zen1 CPU with current MSVC the recursiveFn is about 10% faster. For my Phenom II x4 945 with g++ 11.1.x both functions have the same performance.
Keep in mind that this is almost the worst case since the body of the funtion is very small. If it is larger the part of the recursive function call itself is smaller.
You're trying to capture a variable (sum) you're in the middle of defining. That can't be good.
I don't think truely self-recursive C++0x lambdas are possible. You should be able to capture other lambdas, though.
Here is the final answer for the OP. Anyway, Visual Studio 2010 does not support capturing global variables. And you do not need to capture them because global variable is accessable globally by define. The following answer uses local variable instead.
#include <functional>
#include <iostream>
template<typename T>
struct t2t
{
typedef T t;
};
template<typename R, typename V1, typename V2>
struct fixpoint
{
typedef std::function<R (V1, V2)> func_t;
typedef std::function<func_t (func_t)> tfunc_t;
typedef std::function<func_t (tfunc_t)> yfunc_t;
class loopfunc_t {
public:
func_t operator()(loopfunc_t v)const {
return func(v);
}
template<typename L>
loopfunc_t(const L &l):func(l){}
typedef V1 Parameter1_t;
typedef V2 Parameter2_t;
private:
std::function<func_t (loopfunc_t)> func;
};
static yfunc_t fix;
};
template<typename R, typename V1, typename V2>
typename fixpoint<R, V1, V2>::yfunc_t fixpoint<R, V1, V2>::fix = [](tfunc_t f) -> func_t {
return [f](fixpoint<R, V1, V2>::loopfunc_t x){ return f(x(x)); }
([f](fixpoint<R, V1, V2>::loopfunc_t x) -> fixpoint<R, V1, V2>::func_t{
auto &ff = f;
return [ff, x](t2t<decltype(x)>::t::Parameter1_t v1,
t2t<decltype(x)>::t::Parameter1_t v2){
return ff(x(x))(v1, v2);
};
});
};
int _tmain(int argc, _TCHAR* argv[])
{
auto term = [](int a)->int {
return a*a;
};
auto next = [](int a)->int {
return ++a;
};
auto sum = fixpoint<int, int, int>::fix(
[term,next](std::function<int (int, int)> sum1) -> std::function<int (int, int)>{
auto &term1 = term;
auto &next1 = next;
return [term1, next1, sum1](int a, int b)mutable ->int {
if(a>b)
return 0;
else
return term1(a) + sum1(next1(a),b);
};
});
std::cout<<sum(1,10)<<std::endl; //385
return 0;
}
This answer is inferior to Yankes' one, but still, here it goes:
using dp_type = void (*)();
using fp_type = void (*)(dp_type, unsigned, unsigned);
fp_type fp = [](dp_type dp, unsigned const a, unsigned const b) {
::std::cout << a << ::std::endl;
return reinterpret_cast<fp_type>(dp)(dp, b, a + b);
};
fp(reinterpret_cast<dp_type>(fp), 0, 1);
You need a fixed point combinator. See this.
or look at the following code:
//As decltype(variable)::member_name is invalid currently,
//the following template is a workaround.
//Usage: t2t<decltype(variable)>::t::member_name
template<typename T>
struct t2t
{
typedef T t;
};
template<typename R, typename V>
struct fixpoint
{
typedef std::function<R (V)> func_t;
typedef std::function<func_t (func_t)> tfunc_t;
typedef std::function<func_t (tfunc_t)> yfunc_t;
class loopfunc_t {
public:
func_t operator()(loopfunc_t v)const {
return func(v);
}
template<typename L>
loopfunc_t(const L &l):func(l){}
typedef V Parameter_t;
private:
std::function<func_t (loopfunc_t)> func;
};
static yfunc_t fix;
};
template<typename R, typename V>
typename fixpoint<R, V>::yfunc_t fixpoint<R, V>::fix =
[](fixpoint<R, V>::tfunc_t f) -> fixpoint<R, V>::func_t {
fixpoint<R, V>::loopfunc_t l = [f](fixpoint<R, V>::loopfunc_t x) ->
fixpoint<R, V>::func_t{
//f cannot be captured since it is not a local variable
//of this scope. We need a new reference to it.
auto &ff = f;
//We need struct t2t because template parameter
//V is not accessable in this level.
return [ff, x](t2t<decltype(x)>::t::Parameter_t v){
return ff(x(x))(v);
};
};
return l(l);
};
int _tmain(int argc, _TCHAR* argv[])
{
int v = 0;
std::function<int (int)> fac =
fixpoint<int, int>::fix([](std::function<int (int)> f)
-> std::function<int (int)>{
return [f](int i) -> int{
if(i==0) return 1;
else return i * f(i-1);
};
});
int i = fac(10);
std::cout << i; //3628800
return 0;
}