C++ Shorten subsequent function calls
Asked Answered
I

2

4

I try to find a way in C++17 to shorten following function calls:

GetCurrentContext()->GetEntityManager()->CreateEntity();

maybe to something like:

EM()->CreateEntity();

I tried a function pointer, but this is only valid for static functions:

constexpr auto &EM = GetContext()->GetEntityManager;
// error: reference to non-static member function must be called;

Is there a better solution than using a Macro?

#define EM GetContext()->GetEntityManager

When using an inline function call, i'm afraid, that the compiler will ignore this and i have an unnessessary overhead:

inline EntityManager* EM() { return GetCurrentContext->GetEntityManager(); }

Also this seems to be the wrong way to go, because i'm looking for an alias, not for another function to define.

EDIT:

Every Context has an EntityManager and the current Context can change during runtime. So i'm really looking for an alias, not for a const pointer to what the function returns.

UPDATE:

I found this Question. With return type auto, the inline function becomes independet from the original return type. Even if the original function will get changed in future, the alias need not be touched again. And with trust in compiler optimization this will really become a real alias.

So i think (In consideration of the answers and comments) the best solution is to do the following:

inline decltype(auto) EM() { return GetCurrentContext()->GetEntityManager(); }
Iodic answered 17/5, 2018 at 23:2 Comment(3)
When using an inline function call, i'm afraid, that the compiler will ignore this and i have an unnessessary overhead: Compilers are really good at this type of optimization. You could always check the assembly to confirm it is being done.Frostbite
You might want decltype(auto) instead of auto. If GetEntityManager() ever changes to return a reference (maybe a reference to smart pointer??), decltype(auto) will preserve the reference type, but just auto will not.Collator
always inline can be used instead of inline to force it for gcc.Feck
F
0
  1 #include <iostream>
  2 #include <string>
  3
  4 using namespace std;
  5
  6 class A {
  7   public:
  8    std::string x;
  9    A () {
 10      x += "a";
 11    }
 12
 13    std::string ax() {  //imagine this to be some object.
 14     return x;
 15    }
 16 };
 17
 18 int main () {
 19   A a;
 20   auto y = [] (decltype(a)& a) {
 21     return [&a] () {
 22       return a.ax(); //imagine this to be a big chain like yours. I just wanted to give you a working example, so I'm not doing your calls.
 23     };
 24   };
 25   std::cout << y(a)().at(0) << std::endl; //TADA!! this works
 26   return 1;
 27 }

This can be simplified, and I will leave it upto you. I'm just illustrating how to alias, (without even knowing the types).

you can do something similar with function pointers and then alias as many steps as you like and return at whichever stage you want.

The idea is of having a lambda inside another lambda, this way you do not have to worry that the object changed since it is going to do forwarding not store the object. This way all functions in the chain are called at each invocation of the lamba as it returns the inner lambda that you invoke.

If you think carefully, you can store the function, you don't need to do y(a), it was written in a rush.

Feck answered 18/5, 2018 at 0:46 Comment(3)
Doesn't calling a lambda functions means overhead, because it is stored on the stack?Iodic
Not really, it depends on what kind of overhead you are talking about. a Lambda would be (1 + 1 + 1)byte (since we are capturing an outside var, and one inner lambda). This removes the boilerplate code that you would put, should you make it a function.Feck
I've heard that lambdas can be as expensive as virtual functions when there are too many bytes asigned. So your code works with a function depth of about 4 or lessIodic
C
-1
auto const p = GetCurrentContext()->GetEntityManager();
p->CreateEntity();

Under reasonable assumptions of what the code is about.

There is also an assumption, implicit in your question, that the result from GetEntityManager will be the same in each call in the original code.

Chief answered 17/5, 2018 at 23:7 Comment(6)
Every Context has it's EntityManager and the Context can change. So i can't use a const expression. I really looking for an alias (i will edit my question).Iodic
auto& p or const auto& p but yesGoatsucker
@kaiser: A reference is an alias. That's literally its purpose.Goatsucker
@Iodic You're conflating constness of the pointer variable with constness of what it points at.Chief
@LightnessRacesinOrbit: There is no need for the reference, it just introduces an unneeded and misleading indirection. The result is already a pointer or class type iterator. Unless the code is of very ungood design.Chief
Lets assume all context are on a vector. when there is a reallocation, the old pointer is not pointing correct anymore. This isn't really the case but such things may happen and the const pointer is not error proof.Iodic

© 2022 - 2024 — McMap. All rights reserved.