Another strange question. Brought to you by Discovering Modern C ++ Gottschlig. I am trying to write a template that returns a functor that uses a certain function recursively predetermined number of times. Like that:

template<typename Func, typename X, int N> class Recurs { public: Recurs(Func f):f(f){} X operator()(X x) { return f(Recurs<Func,X,N-1>(f)(x)); } private: Func f; }; template<typename Func, typename X> class Recurs<Func,X,1> { public: Recurs(Func f):f(f){} X operator()(X x) { return f(x); } private: Func f; }; 

Since the use in the spirit

 auto f = [](double x) { return cos(x); }; Recurs<decltype(f),double,10> r(f); r(0.1); 

does not warm the soul, did this function:

 template<int N, typename X, typename Func> auto calc_N(Func f, X x) -> decltype(f(x)) { return Recurs<Func,X,N>(f)(x); } 

The function itself derives types from the values ​​passed, so that it can be calculated as

 calc_N<10>(f,0.1); 

But I didn’t like the Recurs... object being created every time Recurs... I would like to receive it once, and call it as a functor - like,

 template<int N, typename Func> decltype(auto) make_N(Func f) ... auto g = make_N<10>(f); g(0.1); 

And here I have a plug. I wrote something like this -

 template<int N, typename Func> decltype(auto) make_N(Func f) { return Recurs<Func,???,N>(f); } 

but what should I write instead of ??? . In principle, in this case, both the type of the argument f and the type of its return value will suit me (they must be the same for recursion), but how to write them?

And yet - as I recall, decltype(auto) is already C ++ 14. Is it possible to create such a thing on younger versions of the language, and how?

    2 answers 2

    Nothing you do not write there, because in general terms, it is impossible to understand what type of argument is expected. As well as displaying the return value, in general, will not succeed. What does it mean in general? This means that for pointers to functions this can be done, but for functors it is not.

    But why not do differently? Simply remove X from Recurs and leave it local to call operator()() :

     template<typename Func, int N> class Recurs { public: Recurs(Func f):f(f) {} template<typename X> X operator()(X x) { return f(Recurs<Func, N - 1>(f)(x)); } private: Func f; }; 

    And everything will work as you wanted.

    • Pancake. "As I myself did not talk" (c) :) Thank you! - Harry
    • And you can ask a question - on the sly :) - and how, for example, can you pass a function that is overloaded for different types? For example, make_N<10>(cos) - how to clarify that I want to transfer cos , which is for double , and not some other? - Harry
    • @Harry, you need to make an explicit cast: make_N<10>(static_cast<double(*)(double)>(cos)) - ixSci
    • Thanks again! :) - Harry

    That is, you want instead, for example

     int calcSum(int count) { int sum = 0; for (int n = 0; n < count; ++n) ++sum; return sum; } ... for (int n = 0; n < 10; ++n) { int sum = calcSum(10); ... } 

    that was

     template<int count> int calcSum() { int sum = 0; for (int n = 0; n < count; ++n) ++sum; return sum; } ... for (int n = 0; n < 10; ++n) { int sum = calcSum<n>(); ... } 

    And it did not create 10 identical functions.

    There are 2 options. The first option is to declare the function inline .

    The second option is:

     void incSum(int n, int &sum) { if (n > 0) incSum(n-1, ++sum); } int calcSum(int n) { int sum = 0; incSum(n, sum); return sum; } ... for (int n = 0; n < 10; ++n) { int sum = calcSum(n); ... } 

    Let us turn to the templates:

     template<typename CountT, typename SumT> void incSum(CountT n, SumT &sum) { if (n > 0) incSum(n-1, ++sum); } template<typename CountT, typename SumT> SumT calcSum(CountT n) { SumT sum = 0; incSum<CountT, SumT>(n, sum); return sum; } ... for (int n = 0; n < 10; ++n) { int sum = calcSum<int, int>(n); ... } 

    Summarize the algorithm:

     template<typename CountT, typename SumT> class FuncT { public: virtual void f(CountT n, SumT &sum) = 0; }; template<typename CountT, typename SumT> class IncSumT : public FuncT<CountT, SumT> { public: void f(CountT n, SumT &sum) { if (n > 0) incSum(n-1, ++sum); } }; template<typename CountT, typename SumT> SumT calcSum(CountT n, FuncT<CountT, SumT> &func) { SumT sum = 0; func.f(n, sum); return sum; } ... IncSumT<int, int> ist; for (int n = 0; n < 10; ++n) { int sum = calcSum<int, int>(n, ist); ... } 
    • You did not understand. I am looking for a generic solution with templates. And I’m looking for, like me, passing a functor to a template function, to get the type returned by this function in this template. What you are proposing is a recursion of ordinary functions, not template functions. Here we all know the types in advance. - Harry