-1

i am making some callback system and i wonder if i can reserve function reference to unordered_map so that i can invoke it later.

float func_imp(float x)
{
    return x;
}
int main()
{
    using Tumap = unordered_map<int, float(&)(float)>;
    Tumap umap;
    umap.emplace(0, func_imp);
    (umap[0])(10.1); //a reference type cannot be value-initialized

    using Tvec = vector<float(&)(float)>;
    Tvec uvec; // pointer to reference is illegal
    //uvec.emplace_back(func_imp);
}

Is it possible to use this type of containers to reserve callback functions? if not, is it the only way to use function pointer?

liiight
  • 25
  • 1
  • 7
  • 2
    Why do you want to use function references, what do you think that accomplishes that a function pointer can't do? – Sam Varshavchik Jan 19 '21 at 04:05
  • 1
    You can use [std::function](https://en.cppreference.com/w/cpp/utility/functional/function). – Galik Jan 19 '21 at 04:06
  • @SamVarshavchik i just thought there is no need to make dereference. – liiight Jan 19 '21 at 04:06
  • What dereference? Functions are not data. A function pointer is just an abstraction for the code that underlies the function. Nothing is ever "dereferenced" via a function pointer. – Sam Varshavchik Jan 19 '21 at 04:09
  • If you are motivated by some kind of preconception about optimizing for speed, then you are mistaken and also looking in the wrong place. Regarding the need to dereference, you're also mistaken -- that's already taken care of by function-calling syntax. – paddy Jan 19 '21 at 04:10
  • 1
    You are looking for `umap.at(0)(10.1);`. –  Jan 19 '21 at 04:11
  • Frank, this should be an answer – Jeffrey Jan 19 '21 at 04:12
  • @Jeffrey I'm typing an answer right now, but it is verbose, and this quick comment might help in the meantime. –  Jan 19 '21 at 04:13

2 Answers2

2

Regardless of wether this is something you should be doing or not (the comments under your question are covering this already), it's still worth answering your question as is.

The [] operator of map types is a veritable swiss army knife. You can do a lot of things with it.

  • You can assign a value.
  • You can lookup the value.
  • You can lookup a value even if it doesn't exist yet.

Because of this, using that operator imposes some requirements for whatever type is stored in the map. In this specific case, you are running into the requirement that it has to be value-initializable, which references cannot be.

This applies to regular references as well by the way, not just function references.

So the answer is: You can store references in a map as much as you like as long as you don't use any function of the map that requires the reference to do something it's not allowed to.

In this case, you can use umap.at(0)(10.1);. One of the big differences between [] and at() is that if the key is not set yet, at() will throw an exception instead of creating a value-initialized value.

  • Note that `[]` doesn't create a default initialised value in case it doesn't exist; it creates a value initialised one instead. – eerorika Jan 19 '21 at 05:14
2

Is it possible to use this type of containers to ...

Regardless of how this sentence continues: No, it is not possible to use this type of containers. Specifically, element type of no standard container can be a reference. Reference types do not satisfy the requirements that containers have for their element type (at least not when using the standard allocator).

if not, is it the only way to use function pointer?

No, function pointer is not the only way, but it is a way that works.

Other alternatives are function objects such as an erasing function wrapper such as std::function, or a reference wrapper such as std::reference_wrapper.

i just thought there is no need to make dereference.

If you mean syntactically, then I have good news that make your concern irrelevant: There is no need to explicitly indirect through a pointer to function. The indirection is implicit just like with function references. Their call syntax is identical Example:

float(&ref)(float) = func_imp;
float(*ptr)(float) = func_imp;
ref(42.);
ptr(42.);

As such, you needen't worry.

If you are talking about having to indirect through the pointer at runtime at the cost of performance, I have bad news that make your concern irrelevant: References are also a form of indirection just as much as pointers are. They are (typically) not an optimisation.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • I would use `std::function` in such case period. Yes there is a slight overhead but benefits overcome that significantly. – Slava Jan 19 '21 at 05:29