【问题标题】:C++ Shorten subsequent function callsC++ 缩短后续函数调用
【发布时间】:2018-10-28 07:44:20
【问题描述】:

我尝试在 C++17 中找到一种方法来缩短以下函数调用:

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

可能是这样的:

EM()->CreateEntity();

我尝试了一个函数指针,但这仅对静态函数有效:

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

有没有比使用宏更好的解决方案?

#define EM GetContext()->GetEntityManager

当使用内联函数调用时,我担心编译器会忽略这一点,我有不必要的开销:

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

这似乎也是错误的方法,因为我正在寻找一个别名,而不是另一个要定义的函数。

编辑:

每个 Context 都有一个 EntityManager,并且当前 Context 可以在运行时更改。所以我真的在寻找一个别名,而不是一个指向函数返回的 const 指针。

更新:

我找到了this 问题。使用返回类型 auto,内联函数变得独立于原始返回类型。即使将来更改原始功能,也无需再次触摸别名。并且相信编译器优化,这将真正成为一个真正的别名。

所以我认为(考虑到答案和 cmets)最好的解决方案是执行以下操作:

inline decltype(auto) EM() { return GetCurrentContext()->GetEntityManager(); }

【问题讨论】:

  • 当使用内联函数调用时,我担心编译器会忽略这一点,我会有不必要的开销: 编译器非常擅长这种类型的优化。您可以随时检查程序集以确认它正在完成。
  • 您可能需要decltype(auto) 而不是auto。如果 GetEntityManager() 曾经更改为返回引用(可能是对智能指针的引用??),decltype(auto) 将保留引用类型,但 auto 不会。
  • always inline 可以用来代替 inline 来强制它用于 gcc。

标签: c++ macros inline c++17


【解决方案1】:
  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 }

这可以简化,我将由您决定。我只是在说明如何使用别名(甚至不知道类型)。

您可以使用函数指针执行类似的操作,然后为任意多个步骤设置别名,并在您想要的任何阶段返回。

这个想法是在另一个 lambda 中包含一个 lambda,这样您就不必担心对象已更改,因为它会进行转发而不是存储对象。这样,链中的所有函数都会在每次调用 lambda 时被调用,因为它会返回您调用的内部 lambda。

如果你仔细想想,你可以存储函数,你不需要做y(a),它是匆忙写的。

【讨论】:

  • 不调用 lambda 函数意味着开销,因为它存储在堆栈上?
  • 不是真的,这取决于你在谈论什么样的开销。一个 Lambda 将是 (1 + 1 + 1)byte (因为我们正在捕获一个外部 var 和一个内部 lambda)。如果您将其设为函数,这将删除您将放置的样板代码。
  • 我听说当分配的字节太多时,lambda 可能与虚函数一样昂贵。因此,您的代码可以使用大约 4 或更少的函数深度
【解决方案2】:
auto const p = GetCurrentContext()->GetEntityManager();
p->CreateEntity();

在对代码内容的合理假设下。

还有一个假设,隐含在您的问题中,GetEntityManager 的结果在原始代码中的每次调用中都将相同。

【讨论】:

  • 每个 Context 都有它的 EntityManager 并且 Context 可以改变。所以我不能使用 const 表达式。我真的在寻找别名(我会编辑我的问题)。
  • auto&amp; pconst auto&amp; p 但是是的
  • @kaiser:引用是别名。这就是它的真正目的。
  • @kaiser 您将指针变量的常量与它所指向的常量混为一谈。
  • @LightnessRacesinOrbit:不需要引用,它只是引入了一个不需要和误导性的间接。结果已经是一个指针或类类型迭代器。除非代码的设计非常糟糕。
猜你喜欢
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多