0

I have a dilemma about how I should pass a function pointer that will be used extensively by a class throughout the object lifetime. I have thought of 2 solutions:

  • Passing the function pointer to the constructor and storing it inside the class:
    using Func = int(*)(int);

    class A
    {
    public:
        explicit A(int n, Func f) 
            : _f(f), _n(n)
        {}

        int Process()
        {
            return f(n);
        }

    private:
        Func _f;
        int _n;
    };
  • Or using a template parameter:
    using Func = int(*)(int);

    template<Func f>
    class A
    {
    public:
        explicit A(int n) 
            : _n(n)
        {}

        int Process()
        {
            return f(n);
        }

    private:
        int _n;
    };

I think the template solution is more elegant but I am not really sure if it is the best solution. And as a subsidiary question in the template solution, if only the Process method is using the template parameter can I still put the constructor in a source file and keep the Process method in the header file?

2A-66-42
  • 554
  • 1
  • 5
  • 18
  • 1
    Another benefit of the template approach is that any constraints that you impose on the function can be enforced at compile time. – Mansoor Oct 12 '19 at 20:13

2 Answers2

2

Passing f as a template parameter will result in a separate instantiation of the template for each different value of f. If the code size implications of this worry you, don't use a template. If not, and execution time is of paramount importance, then do.

An example of where using a template parameter can speed up execution is std::sort. If you pass a conventional function pointer for the comparison function (as in the C-style qsort), then the time to call it often accounts for a large part of the time to perform the sort. OTOH, std::sort can inline simple comparison functions, which is faster.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • Well the performance improvement was what I was counting on and for the separate instantiations I don't really care since the function pointer will probably be unique. I'm using here to separate implementations(obviously not shown in this simple example) relying on different libraries. – 2A-66-42 Oct 12 '19 at 20:22
0

With minor exceptions, templates must be implemented in header files. This is a problem if you have and API and want to hide how a proprietary piece of code is implemented, for instance, as anyone could simply open the header and look at it.

It also could increase compile time, as the template class needs to get created by the compiler at compile time, vs. getting linked in by the linker.

If neither of these problems bother you, then templates are probably a good way to go here. For one, as you say, it is more eloquent and for another they are quite flexible. If you wake up tomorrow and want to use a different type of function pointer, you are quite free to do so.

Of course, the final decision is up to you, but hopefully now you know some of the pros and cons of each.


Edit: Somehow I missed the last part of your question.

So, any templated part of your code must go in the header. Since your whole class is templated, then you can't put it in a source file.

What you can do instead is make only function that accepts it as a parameter itself templated:

    class A
    {
    public:
        explicit A(int n); // an go in C++ now

        template<Func f>
        int Process()
        {
            return f(n);
        }
        // ...
    };

However, doing it that way will allow Process to accept any function pointer independent of the class. That is, A is no longer bound to a specific f, but rather an individual call to Process is bound to an f. That may not be what you want. Instead, it may be better to do option 1 than my suggested option 3. But again, that's up to you.

  • I have seen the second question you are referring to and I know that templates have to be implemented in header files to be usable with different parameters. My subsidiary question was more along the line of whether or not I could have the non-templated bits in the source file and the rest in the header. Wouldn't the compiler still get the header with the template parameter ? – 2A-66-42 Oct 12 '19 at 20:30