-3

I want to store a function, or a reference thereto, in a class as member variable. I am aware of both storing a function pointer as well as std::function or boosts equivalent. However, I recently read that using pointers results in a call overhead compared to template parameters. In that search I stumbled upon this post, but I fail to reproduce working code from the answer. Here is what I tried, following some of the answers:

template<typename ftype>
class MyClass
{
private:
    ftype func;

public:
    MyClass(ftype func_)
    :func(func_)
    {}
};

double dosth(double x)
{
    return x*x;
}

int main()
{
    MyClass<decltype(dosth)> entity(dosth);
}

However, it results in the error:

error: data member instantiated with function type 'double (double)'

note: in instantiation of template class 'MyClass< double (double)>' requested here

I'm not sure where the exact problem lies, but I would like the exact function type to be inputted at compile time.

So my question is: Writing a class that somehow needs the information of a function that will repeatedly be called (and only called), what can I do to avoid said overhead?

Community
  • 1
  • 1
bernhard_e
  • 37
  • 5
  • 3
    Are you asking about overhead or about getting code to compile? – juanchopanza Feb 26 '18 at 06:45
  • @juanchopanza I am asking about ways to circumvent said overhead and only showed what I tried (and failed with) with that code. I was thinking that this direction, relating to the linked question, might be the correct one and maybe I only made a stupid mistake that can easily be fixed to solve the problem. – bernhard_e Feb 26 '18 at 06:47
  • 1
    Do you have a real performance problem, or do you just do premature optimization? – Rudi Feb 26 '18 at 06:48
  • 1
    To fix the compiler error, you can do either `ftype* func;` or `MyClass entity(dosth);`. As for the question about overhead. I think you need to declare `func` as inline and/or make it a `std::function`. – Code-Apprentice Feb 26 '18 at 06:49
  • 1
    Your compiler error has nothing to do with overhead. Better ask one clear question about one thing. – juanchopanza Feb 26 '18 at 06:49
  • "function pointers have call overhead compared to template parameters" - first line of the first comment below the top answer. Declaring as std::function will probably not help the performance, will it? And yes, I actually have a performance problem on a larger project where I tried to template an algorithm in such a class. The function stored (at this time as function pointer) is called repeatedly and that's why I'm trying to find alternatives. – bernhard_e Feb 26 '18 at 06:53
  • The usual pre-C++17 approach to the problem of template parameters with "strange" types is to wrap your constructor with a template function and let template type deduction deal with it. – Matteo Italia Feb 26 '18 at 07:03
  • @juanchopanza As I said, the question is about the overhead, the code is my failed attempt to solve it. Could you explain what is not clear in the question? – bernhard_e Feb 26 '18 at 07:05

2 Answers2

1

The other comments already explained how to make it compile, but be assured that this doesn't fix your performance problem.

First of all, you still have a function pointer in your wrapper, and it's not much different from a std::function in it's most trivial form. Congratulations on reinventing the wheel.

A template would only improve things, if not just the function signature, but rather the actual function was the template parameter. Only then the compiler would had been able to resolve the function call at compile time and apply optimizations such as inlining or static evaluation.

It's the lack of these optimizations which make function pointers so expensive. The actual invocation of the function pointer has no real impact, that is what processors have a branch prediction for.

Ext3h
  • 5,713
  • 17
  • 43
  • thank you, this sounds promising, But how would I use the function as template parameter? straight forward doing this I get "template argument for template type parameter must be a type" – bernhard_e Feb 26 '18 at 07:28
  • @bernharde See e.g. https://stackoverflow.com/questions/1174169/function-passed-as-template-argument (Look at the example in the question, not at the answer.) – Ext3h Feb 26 '18 at 07:32
  • thanks a lot, that helps. But it requires me to know the function signature pre-compile time, it seems? – bernhard_e Feb 26 '18 at 07:53
  • @bernhard_e Yes and no. You should be able to say just `class functionname` in the template parameter instead of using the full signature. But the compiler does have to know, yes. – Ext3h Feb 26 '18 at 13:39
0

I think you are looking at a non-existent problem. From the accepted answer of the question you linked to:

+-------------------+--------------+---------------+----------------+
|                   | function ptr | std::function | template param |
+===================+==============+===============+================+
| can capture       |    no(1)     |      yes      |       yes      |
| context variables |              |               |                |
+-------------------+--------------+---------------+----------------+
| no call overhead  |     yes      |       no      |       yes      |
| (see comments)    |              |               |                |
+-------------------+--------------+---------------+----------------+
| can be inlined    |      no      |       no      |       yes      |
| (see comments)    |              |               |                |
+-------------------+--------------+---------------+----------------+
  ...

If not being able to support inlining is your only problem, I am going to say, you don't have much to worry about.

When push comes to shove, you can wrap an inline function in a class template and use the class template.


Update, in response to OP's commment.

Let's say you wanted to use the function

double square(double in) { return in*in; }

It wan be wrapped in a class template as:

template <typename T> struct Square
{
    T operator() const (T in) { return in*in; }
};

Now you can use Square<double> as a type instead of square as a function pointer.

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • thanks for your answer, but can you specify a little what you mean by "wrap an inline function in a class template and use the class template"? – bernhard_e Feb 26 '18 at 07:10
  • Uh, you also mixed up on the template part. This isn't about using a type as a template parameter, but rather an actual function. What you did is merely wrapping an templated function in an unnecessary struct. – Ext3h Feb 26 '18 at 07:24