What is the most efficient way to pass a non generic function?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
11
down vote

favorite
1












I am learning functional programming in C++. My intention is to pass a non generic function as argument. I know about the template method, however I would like to restrict the function signature as part of the API design. I worked out 4 different methods example on cpp.sh:



// Example program
#include <iostream>
#include <string>
#include <functional>

typedef int(functor_type)(int);


int by_forwarding(functor_type &&x)
return x(1);


int functor_by_value(functor_type x)
return x(1);


int std_func_by_value(std::function<functor_type> x)
return x(1);


int std_func_by_forwarding(std::function<functor_type> &&x)
return x(1);


int main()

std::cout << functor_by_value((int a)return a;); // works
std::cout << std_func_by_value((int a)return a;); // works
std::cout << std_func_by_forwarding(std::move((int a)return a;)); // works

//std::cout << by_forwarding((int a)return a;); // how to move lambda with forwarding ?



Is any of the above attempts correct? If not, how do i achieve my goal?







share|improve this question




















  • prog.cc:29:41: warning: moving a temporary object prevents copy elision :) clang warnings ftw!
    – hellow
    Aug 16 at 9:13






  • 5




    Short answer: int functor_by_value(functor_type x).
    – George
    Aug 16 at 9:15











  • std::invoke if you have access to C++17
    – Madden
    Aug 16 at 9:17










  • Lambdas are anonymous, therefore you can only grab its type through type deduction.
    – Passer By
    Aug 16 at 9:18










  • It depends on meaning you put into "pass a non generic function" First two variants accept a reference or a pointer to function. 3rd and 4th variant accept an object or an rvalue reference to object with overloaded operator (). So every x has an operator () so usual calling syntax x(1); works, however none of them are functions.
    – VTT
    Aug 16 at 9:20















up vote
11
down vote

favorite
1












I am learning functional programming in C++. My intention is to pass a non generic function as argument. I know about the template method, however I would like to restrict the function signature as part of the API design. I worked out 4 different methods example on cpp.sh:



// Example program
#include <iostream>
#include <string>
#include <functional>

typedef int(functor_type)(int);


int by_forwarding(functor_type &&x)
return x(1);


int functor_by_value(functor_type x)
return x(1);


int std_func_by_value(std::function<functor_type> x)
return x(1);


int std_func_by_forwarding(std::function<functor_type> &&x)
return x(1);


int main()

std::cout << functor_by_value((int a)return a;); // works
std::cout << std_func_by_value((int a)return a;); // works
std::cout << std_func_by_forwarding(std::move((int a)return a;)); // works

//std::cout << by_forwarding((int a)return a;); // how to move lambda with forwarding ?



Is any of the above attempts correct? If not, how do i achieve my goal?







share|improve this question




















  • prog.cc:29:41: warning: moving a temporary object prevents copy elision :) clang warnings ftw!
    – hellow
    Aug 16 at 9:13






  • 5




    Short answer: int functor_by_value(functor_type x).
    – George
    Aug 16 at 9:15











  • std::invoke if you have access to C++17
    – Madden
    Aug 16 at 9:17










  • Lambdas are anonymous, therefore you can only grab its type through type deduction.
    – Passer By
    Aug 16 at 9:18










  • It depends on meaning you put into "pass a non generic function" First two variants accept a reference or a pointer to function. 3rd and 4th variant accept an object or an rvalue reference to object with overloaded operator (). So every x has an operator () so usual calling syntax x(1); works, however none of them are functions.
    – VTT
    Aug 16 at 9:20













up vote
11
down vote

favorite
1









up vote
11
down vote

favorite
1






1





I am learning functional programming in C++. My intention is to pass a non generic function as argument. I know about the template method, however I would like to restrict the function signature as part of the API design. I worked out 4 different methods example on cpp.sh:



// Example program
#include <iostream>
#include <string>
#include <functional>

typedef int(functor_type)(int);


int by_forwarding(functor_type &&x)
return x(1);


int functor_by_value(functor_type x)
return x(1);


int std_func_by_value(std::function<functor_type> x)
return x(1);


int std_func_by_forwarding(std::function<functor_type> &&x)
return x(1);


int main()

std::cout << functor_by_value((int a)return a;); // works
std::cout << std_func_by_value((int a)return a;); // works
std::cout << std_func_by_forwarding(std::move((int a)return a;)); // works

//std::cout << by_forwarding((int a)return a;); // how to move lambda with forwarding ?



Is any of the above attempts correct? If not, how do i achieve my goal?







share|improve this question












I am learning functional programming in C++. My intention is to pass a non generic function as argument. I know about the template method, however I would like to restrict the function signature as part of the API design. I worked out 4 different methods example on cpp.sh:



// Example program
#include <iostream>
#include <string>
#include <functional>

typedef int(functor_type)(int);


int by_forwarding(functor_type &&x)
return x(1);


int functor_by_value(functor_type x)
return x(1);


int std_func_by_value(std::function<functor_type> x)
return x(1);


int std_func_by_forwarding(std::function<functor_type> &&x)
return x(1);


int main()

std::cout << functor_by_value((int a)return a;); // works
std::cout << std_func_by_value((int a)return a;); // works
std::cout << std_func_by_forwarding(std::move((int a)return a;)); // works

//std::cout << by_forwarding((int a)return a;); // how to move lambda with forwarding ?



Is any of the above attempts correct? If not, how do i achieve my goal?









share|improve this question











share|improve this question




share|improve this question










asked Aug 16 at 9:11









Afoxinabox

827




827











  • prog.cc:29:41: warning: moving a temporary object prevents copy elision :) clang warnings ftw!
    – hellow
    Aug 16 at 9:13






  • 5




    Short answer: int functor_by_value(functor_type x).
    – George
    Aug 16 at 9:15











  • std::invoke if you have access to C++17
    – Madden
    Aug 16 at 9:17










  • Lambdas are anonymous, therefore you can only grab its type through type deduction.
    – Passer By
    Aug 16 at 9:18










  • It depends on meaning you put into "pass a non generic function" First two variants accept a reference or a pointer to function. 3rd and 4th variant accept an object or an rvalue reference to object with overloaded operator (). So every x has an operator () so usual calling syntax x(1); works, however none of them are functions.
    – VTT
    Aug 16 at 9:20

















  • prog.cc:29:41: warning: moving a temporary object prevents copy elision :) clang warnings ftw!
    – hellow
    Aug 16 at 9:13






  • 5




    Short answer: int functor_by_value(functor_type x).
    – George
    Aug 16 at 9:15











  • std::invoke if you have access to C++17
    – Madden
    Aug 16 at 9:17










  • Lambdas are anonymous, therefore you can only grab its type through type deduction.
    – Passer By
    Aug 16 at 9:18










  • It depends on meaning you put into "pass a non generic function" First two variants accept a reference or a pointer to function. 3rd and 4th variant accept an object or an rvalue reference to object with overloaded operator (). So every x has an operator () so usual calling syntax x(1); works, however none of them are functions.
    – VTT
    Aug 16 at 9:20
















prog.cc:29:41: warning: moving a temporary object prevents copy elision :) clang warnings ftw!
– hellow
Aug 16 at 9:13




prog.cc:29:41: warning: moving a temporary object prevents copy elision :) clang warnings ftw!
– hellow
Aug 16 at 9:13




5




5




Short answer: int functor_by_value(functor_type x).
– George
Aug 16 at 9:15





Short answer: int functor_by_value(functor_type x).
– George
Aug 16 at 9:15













std::invoke if you have access to C++17
– Madden
Aug 16 at 9:17




std::invoke if you have access to C++17
– Madden
Aug 16 at 9:17












Lambdas are anonymous, therefore you can only grab its type through type deduction.
– Passer By
Aug 16 at 9:18




Lambdas are anonymous, therefore you can only grab its type through type deduction.
– Passer By
Aug 16 at 9:18












It depends on meaning you put into "pass a non generic function" First two variants accept a reference or a pointer to function. 3rd and 4th variant accept an object or an rvalue reference to object with overloaded operator (). So every x has an operator () so usual calling syntax x(1); works, however none of them are functions.
– VTT
Aug 16 at 9:20





It depends on meaning you put into "pass a non generic function" First two variants accept a reference or a pointer to function. 3rd and 4th variant accept an object or an rvalue reference to object with overloaded operator (). So every x has an operator () so usual calling syntax x(1); works, however none of them are functions.
– VTT
Aug 16 at 9:20













4 Answers
4






active

oldest

votes

















up vote
12
down vote



accepted










(based on clarification from comments)



Signature can be restricted by using std::is_invocable:



template<typename x_Action> auto
functor_by_value(x_Action && action)

static_assert(std::is_invocable_r_v<int, x_Action, int>);
return action(1);



online compiler






share|improve this answer






















  • @lubgr Just a habit. I've been working in environment that prohibits implicit object construction.
    – VTT
    Aug 16 at 9:54

















up vote
4
down vote













Other alternative:



template <typename Func>
auto functor_by_value(Func&& f)
-> decltype(std::forward<Func>(f)(1))

return std::forward<Func>(f)(1);






share|improve this answer



























    up vote
    4
    down vote














    however I would like to restrict the function signature as part of the API design.




    So restrict it:



    #include <functional>
    #include <type_traits>
    #include <iostream>

    /// @tparam F is a type which is callable, accepting an int and returning an int
    template
    <
    class F,
    std::enable_if_t
    <
    std::is_convertible_v<F, std::function<int(int)>>
    >* = nullptr
    >
    int myfunc(F &&x)
    return x(1);


    int main()

    auto a = myfunc((int x) std::cout << x << std::endl; return 1; );

    // does not compile
    // auto b = myfunc(() std::cout << "foo" << std::endl; return 1; );






    share|improve this answer
















    • 2




      This would fail when object can be invoked as int (int) but can not be converted to std::function object. For example when object is not copyable / movable but has public: int operator ()(int).
      – VTT
      Aug 16 at 10:00











    • @VTT I do agree - std::function expects function objects to be callable on the const interface, which may or may not be a bug in the standard, depending on how you look at it. However, the OP mentioned that std::function was a candidate for the argument type, so I took a lead from there. I saw your answer (and upvoted). I was not aware of the is_invocable_r_t type trait.
      – Richard Hodges
      Aug 16 at 11:24

















    up vote
    4
    down vote













    As usual, this depends on how good your compiler is today, and how good it will be in the future.



    Currently, compilers are not very good at optimizing std::function. Surprisingly, std::function is a complicated object that sometimes has to allocate memory to maintain stateful lambda functions. It also complicates matters that std::function has to be able to refer to member function, regular functions, and lambdas, and do it in a transparent manner. This transparency has a hefty runtime cost.



    So, if you want the fastest possible code, you should be careful with std::function. For that reason the first variant is the fastest (on today's compilers):



    int functor_by_value(functor_type x) 
    return x(1);



    It simply passes a pointer to a function.



    When stateful lambdas are involved you have only two options. Either pass the lambda as a template argument, or convert to std::function. Hence, if you want the fastest code possible with lambdas (in today's compilers), you'd pass the function as a templated argument.



    Since a lambda function may have a big state, passing it around may copy the big state (when copy elision is not possible). GCC will construct the lambda directly on the parameter list (with no copy), but a nested function will invoke a copy constructor for the lambda. To avoid that, either pass it by const reference (in that case it can't be mutable), or by rvalue reference:



    template<class Func>
    void run2(const Func & f)

    std::cout << "Runningn";
    f();

    template<class Func>
    void run(const Func & f)

    run2(f);

    int main()

    run([s=BigState()]() std::cout << "applyn"; );
    return 0;



    Or:



    template<class Func>
    void run2(Func && f)

    f();

    template<class Func>
    void run(Func && f)

    run2(std::forward<Func>(f));

    int main()

    run([s=BigState()]() std::cout << "applyn"; );
    return 0;



    Without using references, the BigState() will be copied when the lambda is copied.



    UPDATE:
    After reading the question again I see that it wants to restrict the signature



    template<typename Func, 
    typename = std::enable_if_t<
    std::is_convertible_v<decltype(Func(1)), int>>>
    void run2(const Func & f)

    std::cout << "Runningn";
    f();



    This will restrict it to any function that can accept int (possibly with an implicit cast), and returns an int or any type that is implicitly cast to int. However, if you want to accept only function-like objects that accept exactly int and return exactly int you can see if the lambda is convertible to std::function<int(int)>






    share|improve this answer






















      Your Answer





      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      convertImagesToLinks: true,
      noModals: false,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













       

      draft saved


      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51873464%2fwhat-is-the-most-efficient-way-to-pass-a-non-generic-function%23new-answer', 'question_page');

      );

      Post as a guest






























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      12
      down vote



      accepted










      (based on clarification from comments)



      Signature can be restricted by using std::is_invocable:



      template<typename x_Action> auto
      functor_by_value(x_Action && action)

      static_assert(std::is_invocable_r_v<int, x_Action, int>);
      return action(1);



      online compiler






      share|improve this answer






















      • @lubgr Just a habit. I've been working in environment that prohibits implicit object construction.
        – VTT
        Aug 16 at 9:54














      up vote
      12
      down vote



      accepted










      (based on clarification from comments)



      Signature can be restricted by using std::is_invocable:



      template<typename x_Action> auto
      functor_by_value(x_Action && action)

      static_assert(std::is_invocable_r_v<int, x_Action, int>);
      return action(1);



      online compiler






      share|improve this answer






















      • @lubgr Just a habit. I've been working in environment that prohibits implicit object construction.
        – VTT
        Aug 16 at 9:54












      up vote
      12
      down vote



      accepted







      up vote
      12
      down vote



      accepted






      (based on clarification from comments)



      Signature can be restricted by using std::is_invocable:



      template<typename x_Action> auto
      functor_by_value(x_Action && action)

      static_assert(std::is_invocable_r_v<int, x_Action, int>);
      return action(1);



      online compiler






      share|improve this answer














      (based on clarification from comments)



      Signature can be restricted by using std::is_invocable:



      template<typename x_Action> auto
      functor_by_value(x_Action && action)

      static_assert(std::is_invocable_r_v<int, x_Action, int>);
      return action(1);



      online compiler







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Aug 16 at 9:52

























      answered Aug 16 at 9:45









      VTT

      21.1k32143




      21.1k32143











      • @lubgr Just a habit. I've been working in environment that prohibits implicit object construction.
        – VTT
        Aug 16 at 9:54
















      • @lubgr Just a habit. I've been working in environment that prohibits implicit object construction.
        – VTT
        Aug 16 at 9:54















      @lubgr Just a habit. I've been working in environment that prohibits implicit object construction.
      – VTT
      Aug 16 at 9:54




      @lubgr Just a habit. I've been working in environment that prohibits implicit object construction.
      – VTT
      Aug 16 at 9:54












      up vote
      4
      down vote













      Other alternative:



      template <typename Func>
      auto functor_by_value(Func&& f)
      -> decltype(std::forward<Func>(f)(1))

      return std::forward<Func>(f)(1);






      share|improve this answer
























        up vote
        4
        down vote













        Other alternative:



        template <typename Func>
        auto functor_by_value(Func&& f)
        -> decltype(std::forward<Func>(f)(1))

        return std::forward<Func>(f)(1);






        share|improve this answer






















          up vote
          4
          down vote










          up vote
          4
          down vote









          Other alternative:



          template <typename Func>
          auto functor_by_value(Func&& f)
          -> decltype(std::forward<Func>(f)(1))

          return std::forward<Func>(f)(1);






          share|improve this answer












          Other alternative:



          template <typename Func>
          auto functor_by_value(Func&& f)
          -> decltype(std::forward<Func>(f)(1))

          return std::forward<Func>(f)(1);







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Aug 16 at 9:31









          Jarod42

          106k1295166




          106k1295166




















              up vote
              4
              down vote














              however I would like to restrict the function signature as part of the API design.




              So restrict it:



              #include <functional>
              #include <type_traits>
              #include <iostream>

              /// @tparam F is a type which is callable, accepting an int and returning an int
              template
              <
              class F,
              std::enable_if_t
              <
              std::is_convertible_v<F, std::function<int(int)>>
              >* = nullptr
              >
              int myfunc(F &&x)
              return x(1);


              int main()

              auto a = myfunc((int x) std::cout << x << std::endl; return 1; );

              // does not compile
              // auto b = myfunc(() std::cout << "foo" << std::endl; return 1; );






              share|improve this answer
















              • 2




                This would fail when object can be invoked as int (int) but can not be converted to std::function object. For example when object is not copyable / movable but has public: int operator ()(int).
                – VTT
                Aug 16 at 10:00











              • @VTT I do agree - std::function expects function objects to be callable on the const interface, which may or may not be a bug in the standard, depending on how you look at it. However, the OP mentioned that std::function was a candidate for the argument type, so I took a lead from there. I saw your answer (and upvoted). I was not aware of the is_invocable_r_t type trait.
                – Richard Hodges
                Aug 16 at 11:24














              up vote
              4
              down vote














              however I would like to restrict the function signature as part of the API design.




              So restrict it:



              #include <functional>
              #include <type_traits>
              #include <iostream>

              /// @tparam F is a type which is callable, accepting an int and returning an int
              template
              <
              class F,
              std::enable_if_t
              <
              std::is_convertible_v<F, std::function<int(int)>>
              >* = nullptr
              >
              int myfunc(F &&x)
              return x(1);


              int main()

              auto a = myfunc((int x) std::cout << x << std::endl; return 1; );

              // does not compile
              // auto b = myfunc(() std::cout << "foo" << std::endl; return 1; );






              share|improve this answer
















              • 2




                This would fail when object can be invoked as int (int) but can not be converted to std::function object. For example when object is not copyable / movable but has public: int operator ()(int).
                – VTT
                Aug 16 at 10:00











              • @VTT I do agree - std::function expects function objects to be callable on the const interface, which may or may not be a bug in the standard, depending on how you look at it. However, the OP mentioned that std::function was a candidate for the argument type, so I took a lead from there. I saw your answer (and upvoted). I was not aware of the is_invocable_r_t type trait.
                – Richard Hodges
                Aug 16 at 11:24












              up vote
              4
              down vote










              up vote
              4
              down vote










              however I would like to restrict the function signature as part of the API design.




              So restrict it:



              #include <functional>
              #include <type_traits>
              #include <iostream>

              /// @tparam F is a type which is callable, accepting an int and returning an int
              template
              <
              class F,
              std::enable_if_t
              <
              std::is_convertible_v<F, std::function<int(int)>>
              >* = nullptr
              >
              int myfunc(F &&x)
              return x(1);


              int main()

              auto a = myfunc((int x) std::cout << x << std::endl; return 1; );

              // does not compile
              // auto b = myfunc(() std::cout << "foo" << std::endl; return 1; );






              share|improve this answer













              however I would like to restrict the function signature as part of the API design.




              So restrict it:



              #include <functional>
              #include <type_traits>
              #include <iostream>

              /// @tparam F is a type which is callable, accepting an int and returning an int
              template
              <
              class F,
              std::enable_if_t
              <
              std::is_convertible_v<F, std::function<int(int)>>
              >* = nullptr
              >
              int myfunc(F &&x)
              return x(1);


              int main()

              auto a = myfunc((int x) std::cout << x << std::endl; return 1; );

              // does not compile
              // auto b = myfunc(() std::cout << "foo" << std::endl; return 1; );







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Aug 16 at 9:50









              Richard Hodges

              53.6k55597




              53.6k55597







              • 2




                This would fail when object can be invoked as int (int) but can not be converted to std::function object. For example when object is not copyable / movable but has public: int operator ()(int).
                – VTT
                Aug 16 at 10:00











              • @VTT I do agree - std::function expects function objects to be callable on the const interface, which may or may not be a bug in the standard, depending on how you look at it. However, the OP mentioned that std::function was a candidate for the argument type, so I took a lead from there. I saw your answer (and upvoted). I was not aware of the is_invocable_r_t type trait.
                – Richard Hodges
                Aug 16 at 11:24












              • 2




                This would fail when object can be invoked as int (int) but can not be converted to std::function object. For example when object is not copyable / movable but has public: int operator ()(int).
                – VTT
                Aug 16 at 10:00











              • @VTT I do agree - std::function expects function objects to be callable on the const interface, which may or may not be a bug in the standard, depending on how you look at it. However, the OP mentioned that std::function was a candidate for the argument type, so I took a lead from there. I saw your answer (and upvoted). I was not aware of the is_invocable_r_t type trait.
                – Richard Hodges
                Aug 16 at 11:24







              2




              2




              This would fail when object can be invoked as int (int) but can not be converted to std::function object. For example when object is not copyable / movable but has public: int operator ()(int).
              – VTT
              Aug 16 at 10:00





              This would fail when object can be invoked as int (int) but can not be converted to std::function object. For example when object is not copyable / movable but has public: int operator ()(int).
              – VTT
              Aug 16 at 10:00













              @VTT I do agree - std::function expects function objects to be callable on the const interface, which may or may not be a bug in the standard, depending on how you look at it. However, the OP mentioned that std::function was a candidate for the argument type, so I took a lead from there. I saw your answer (and upvoted). I was not aware of the is_invocable_r_t type trait.
              – Richard Hodges
              Aug 16 at 11:24




              @VTT I do agree - std::function expects function objects to be callable on the const interface, which may or may not be a bug in the standard, depending on how you look at it. However, the OP mentioned that std::function was a candidate for the argument type, so I took a lead from there. I saw your answer (and upvoted). I was not aware of the is_invocable_r_t type trait.
              – Richard Hodges
              Aug 16 at 11:24










              up vote
              4
              down vote













              As usual, this depends on how good your compiler is today, and how good it will be in the future.



              Currently, compilers are not very good at optimizing std::function. Surprisingly, std::function is a complicated object that sometimes has to allocate memory to maintain stateful lambda functions. It also complicates matters that std::function has to be able to refer to member function, regular functions, and lambdas, and do it in a transparent manner. This transparency has a hefty runtime cost.



              So, if you want the fastest possible code, you should be careful with std::function. For that reason the first variant is the fastest (on today's compilers):



              int functor_by_value(functor_type x) 
              return x(1);



              It simply passes a pointer to a function.



              When stateful lambdas are involved you have only two options. Either pass the lambda as a template argument, or convert to std::function. Hence, if you want the fastest code possible with lambdas (in today's compilers), you'd pass the function as a templated argument.



              Since a lambda function may have a big state, passing it around may copy the big state (when copy elision is not possible). GCC will construct the lambda directly on the parameter list (with no copy), but a nested function will invoke a copy constructor for the lambda. To avoid that, either pass it by const reference (in that case it can't be mutable), or by rvalue reference:



              template<class Func>
              void run2(const Func & f)

              std::cout << "Runningn";
              f();

              template<class Func>
              void run(const Func & f)

              run2(f);

              int main()

              run([s=BigState()]() std::cout << "applyn"; );
              return 0;



              Or:



              template<class Func>
              void run2(Func && f)

              f();

              template<class Func>
              void run(Func && f)

              run2(std::forward<Func>(f));

              int main()

              run([s=BigState()]() std::cout << "applyn"; );
              return 0;



              Without using references, the BigState() will be copied when the lambda is copied.



              UPDATE:
              After reading the question again I see that it wants to restrict the signature



              template<typename Func, 
              typename = std::enable_if_t<
              std::is_convertible_v<decltype(Func(1)), int>>>
              void run2(const Func & f)

              std::cout << "Runningn";
              f();



              This will restrict it to any function that can accept int (possibly with an implicit cast), and returns an int or any type that is implicitly cast to int. However, if you want to accept only function-like objects that accept exactly int and return exactly int you can see if the lambda is convertible to std::function<int(int)>






              share|improve this answer


























                up vote
                4
                down vote













                As usual, this depends on how good your compiler is today, and how good it will be in the future.



                Currently, compilers are not very good at optimizing std::function. Surprisingly, std::function is a complicated object that sometimes has to allocate memory to maintain stateful lambda functions. It also complicates matters that std::function has to be able to refer to member function, regular functions, and lambdas, and do it in a transparent manner. This transparency has a hefty runtime cost.



                So, if you want the fastest possible code, you should be careful with std::function. For that reason the first variant is the fastest (on today's compilers):



                int functor_by_value(functor_type x) 
                return x(1);



                It simply passes a pointer to a function.



                When stateful lambdas are involved you have only two options. Either pass the lambda as a template argument, or convert to std::function. Hence, if you want the fastest code possible with lambdas (in today's compilers), you'd pass the function as a templated argument.



                Since a lambda function may have a big state, passing it around may copy the big state (when copy elision is not possible). GCC will construct the lambda directly on the parameter list (with no copy), but a nested function will invoke a copy constructor for the lambda. To avoid that, either pass it by const reference (in that case it can't be mutable), or by rvalue reference:



                template<class Func>
                void run2(const Func & f)

                std::cout << "Runningn";
                f();

                template<class Func>
                void run(const Func & f)

                run2(f);

                int main()

                run([s=BigState()]() std::cout << "applyn"; );
                return 0;



                Or:



                template<class Func>
                void run2(Func && f)

                f();

                template<class Func>
                void run(Func && f)

                run2(std::forward<Func>(f));

                int main()

                run([s=BigState()]() std::cout << "applyn"; );
                return 0;



                Without using references, the BigState() will be copied when the lambda is copied.



                UPDATE:
                After reading the question again I see that it wants to restrict the signature



                template<typename Func, 
                typename = std::enable_if_t<
                std::is_convertible_v<decltype(Func(1)), int>>>
                void run2(const Func & f)

                std::cout << "Runningn";
                f();



                This will restrict it to any function that can accept int (possibly with an implicit cast), and returns an int or any type that is implicitly cast to int. However, if you want to accept only function-like objects that accept exactly int and return exactly int you can see if the lambda is convertible to std::function<int(int)>






                share|improve this answer
























                  up vote
                  4
                  down vote










                  up vote
                  4
                  down vote









                  As usual, this depends on how good your compiler is today, and how good it will be in the future.



                  Currently, compilers are not very good at optimizing std::function. Surprisingly, std::function is a complicated object that sometimes has to allocate memory to maintain stateful lambda functions. It also complicates matters that std::function has to be able to refer to member function, regular functions, and lambdas, and do it in a transparent manner. This transparency has a hefty runtime cost.



                  So, if you want the fastest possible code, you should be careful with std::function. For that reason the first variant is the fastest (on today's compilers):



                  int functor_by_value(functor_type x) 
                  return x(1);



                  It simply passes a pointer to a function.



                  When stateful lambdas are involved you have only two options. Either pass the lambda as a template argument, or convert to std::function. Hence, if you want the fastest code possible with lambdas (in today's compilers), you'd pass the function as a templated argument.



                  Since a lambda function may have a big state, passing it around may copy the big state (when copy elision is not possible). GCC will construct the lambda directly on the parameter list (with no copy), but a nested function will invoke a copy constructor for the lambda. To avoid that, either pass it by const reference (in that case it can't be mutable), or by rvalue reference:



                  template<class Func>
                  void run2(const Func & f)

                  std::cout << "Runningn";
                  f();

                  template<class Func>
                  void run(const Func & f)

                  run2(f);

                  int main()

                  run([s=BigState()]() std::cout << "applyn"; );
                  return 0;



                  Or:



                  template<class Func>
                  void run2(Func && f)

                  f();

                  template<class Func>
                  void run(Func && f)

                  run2(std::forward<Func>(f));

                  int main()

                  run([s=BigState()]() std::cout << "applyn"; );
                  return 0;



                  Without using references, the BigState() will be copied when the lambda is copied.



                  UPDATE:
                  After reading the question again I see that it wants to restrict the signature



                  template<typename Func, 
                  typename = std::enable_if_t<
                  std::is_convertible_v<decltype(Func(1)), int>>>
                  void run2(const Func & f)

                  std::cout << "Runningn";
                  f();



                  This will restrict it to any function that can accept int (possibly with an implicit cast), and returns an int or any type that is implicitly cast to int. However, if you want to accept only function-like objects that accept exactly int and return exactly int you can see if the lambda is convertible to std::function<int(int)>






                  share|improve this answer














                  As usual, this depends on how good your compiler is today, and how good it will be in the future.



                  Currently, compilers are not very good at optimizing std::function. Surprisingly, std::function is a complicated object that sometimes has to allocate memory to maintain stateful lambda functions. It also complicates matters that std::function has to be able to refer to member function, regular functions, and lambdas, and do it in a transparent manner. This transparency has a hefty runtime cost.



                  So, if you want the fastest possible code, you should be careful with std::function. For that reason the first variant is the fastest (on today's compilers):



                  int functor_by_value(functor_type x) 
                  return x(1);



                  It simply passes a pointer to a function.



                  When stateful lambdas are involved you have only two options. Either pass the lambda as a template argument, or convert to std::function. Hence, if you want the fastest code possible with lambdas (in today's compilers), you'd pass the function as a templated argument.



                  Since a lambda function may have a big state, passing it around may copy the big state (when copy elision is not possible). GCC will construct the lambda directly on the parameter list (with no copy), but a nested function will invoke a copy constructor for the lambda. To avoid that, either pass it by const reference (in that case it can't be mutable), or by rvalue reference:



                  template<class Func>
                  void run2(const Func & f)

                  std::cout << "Runningn";
                  f();

                  template<class Func>
                  void run(const Func & f)

                  run2(f);

                  int main()

                  run([s=BigState()]() std::cout << "applyn"; );
                  return 0;



                  Or:



                  template<class Func>
                  void run2(Func && f)

                  f();

                  template<class Func>
                  void run(Func && f)

                  run2(std::forward<Func>(f));

                  int main()

                  run([s=BigState()]() std::cout << "applyn"; );
                  return 0;



                  Without using references, the BigState() will be copied when the lambda is copied.



                  UPDATE:
                  After reading the question again I see that it wants to restrict the signature



                  template<typename Func, 
                  typename = std::enable_if_t<
                  std::is_convertible_v<decltype(Func(1)), int>>>
                  void run2(const Func & f)

                  std::cout << "Runningn";
                  f();



                  This will restrict it to any function that can accept int (possibly with an implicit cast), and returns an int or any type that is implicitly cast to int. However, if you want to accept only function-like objects that accept exactly int and return exactly int you can see if the lambda is convertible to std::function<int(int)>







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Aug 21 at 11:53

























                  answered Aug 16 at 9:37









                  Michael Veksler

                  1,320411




                  1,320411



























                       

                      draft saved


                      draft discarded















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51873464%2fwhat-is-the-most-efficient-way-to-pass-a-non-generic-function%23new-answer', 'question_page');

                      );

                      Post as a guest













































































                      Comments

                      Popular posts from this blog

                      What does second last employer means? [closed]

                      List of Gilmore Girls characters

                      Confectionery