13

I'm working on an embedded system, so code size is an issue. Using the standard library ups my binary size by about 60k, from 40k to 100k. I'd like to use std::function, but I can't justify it for 60k. Is there a standalone implementation that I can use, or something similar? I'm using it to implicitly cast lambdas in member functions with bound variables in c++ 11.

Kendrick Taylor
  • 2,218
  • 2
  • 18
  • 21
  • 1
    have you tried boost::function and boost::bind? – juanchopanza Feb 06 '13 at 22:15
  • @juanchopanza: Is it supposed to reduce the code size wrt `std::function`? – Andy Prowl Feb 06 '13 at 22:16
  • Have you considered using a different C++ library, e.g. Dinkumware? – nneonneo Feb 06 '13 at 22:18
  • Probably not, but I can't imagine how a "standalone" implementation would do that. – juanchopanza Feb 06 '13 at 22:20
  • @juanchopanza boost::function and boost::bind use which is what I need anyway. And boost's function.hpp increases my binary size 220k, without even using it. Which puts it well over the flash size on my chip. – Kendrick Taylor Feb 06 '13 at 22:33
  • I think what I might need is a std::function that I can disable exceptions on. I'm using the gnu library, and as far as I can tell I can't disable exceptions. I think that's what's adding the 60k. I currently have exceptions disabled. – Kendrick Taylor Feb 06 '13 at 22:35

2 Answers2

14

Here is simple implementation of std::function-like class template without inclusion of any headers. You can customize the behavior as you wish(like move/forward, empty call response, etc):

live_demo

// Scroll down for example of usage
namespace bicycle
{
    template<typename Result,typename ...Args>
    struct abstract_function
    {
        virtual Result operator()(Args... args)=0;
        virtual abstract_function *clone() const =0;
        virtual ~abstract_function() = default;
    };

    template<typename Func,typename Result,typename ...Args>
    class concrete_function: public abstract_function<Result,Args...>
    {
        Func f;
    public:
        concrete_function(const Func &x)
            : f(x)
        {}
        Result operator()(Args... args) override
        {
            return f(args...);
        }
        concrete_function *clone() const override
        {
            return new concrete_function{f};
        }
    };

    template<typename Func>
    struct func_filter
    {
        typedef Func type;
    };
    template<typename Result,typename ...Args>
    struct func_filter<Result(Args...)>
    {
        typedef Result (*type)(Args...);
    };

    template<typename signature>
    class function;

    template<typename Result,typename ...Args>
    class function<Result(Args...)>
    {
        abstract_function<Result,Args...> *f;
    public:
        function()
            : f(nullptr)
        {}
        template<typename Func> function(const Func &x)
            : f(new concrete_function<typename func_filter<Func>::type,Result,Args...>(x))
        {}
        function(const function &rhs)
            : f(rhs.f ? rhs.f->clone() : nullptr)
        {}
        function &operator=(const function &rhs)
        {
            if( (&rhs != this ) && (rhs.f) )
            {
                auto *temp = rhs.f->clone();
                delete f;
                f = temp;
            }
            return *this;
        }
        template<typename Func> function &operator=(const Func &x)
        {
            auto *temp = new concrete_function<typename func_filter<Func>::type,Result,Args...>(x);
            delete f;
            f = temp;
            return *this;
        }
        Result operator()(Args... args)
        {
            if(f)
                return (*f)(args...);
            else
                return Result{};
        }
        ~function()
        {
            delete f;
        }
    };
}

// ___________________[ Example of usage ]___________________ //

int func1(double)
{
    return 1;
}
struct Functor2
{
    int operator()(double)
    {
        return 2;
    }
};

double func3(bool,int)
{
    return 3.0;
}
struct Functor4
{
    double operator()(bool,int)
    {
        return 4.0;
    }
};

int main()
{
    int res = 10;
    {
        bicycle::function<int(double)> f{func1};

        res -= f(1.0);
        f = Functor2{};
        res -= f(2.0);
    }
    {
        bicycle::function<double(bool,int)> f1;
        f1 = func3;

        bicycle::function<double(bool,int)> f2{f1};
        res -= f2(true,1);

        f1 = Functor4{};
        f2 = f1;
        res -= f2(false,2);
    }
    return res;
}
Evgeny Panasyuk
  • 9,076
  • 1
  • 33
  • 54
  • Privet Evgeny, amazing implementation, but how does it work? why function is defined with one general first and then redefined taking 2 parameters , I quietly don't get the principles how to write such a code :) – barney Feb 20 '16 at 10:03
12

The 60k came from exception handling being added by the compiler, because exceptions were required for std::function. std::function only throws one exception, "bad_function_call". So I removed the code that threw the exception, now it seg faults if an empty function is called, and I saved myself 60k.

Kendrick Taylor
  • 2,218
  • 2
  • 18
  • 21