【问题标题】:Function resolution功能分辨率
【发布时间】:2011-10-24 16:39:46
【问题描述】:

我有很多带有这个签名的函数:

DoSomething(int x, int y, int z, int t, int u, int p);

它们都有相同数量的参数和相同类型的参数。

我希望能够像这样使用它们:

DoSomething(1, 2, 3, 4, 5, 6);

我知道编译器无法区分具有相同签名的函数(它们是完全非法的)。

为此,我想将函数的参数包装在逻辑“构造”中。这并不意味着类或结构。例如:

DoSomething(Construct1(x, y, z), Construct2(t, u, p));
or
DoSomething(Construct1(x, y), Constrcut2(t, u, p, o));

在这种情况下,我可以区分这两个函数并且它们具有相同数量的参数。如果我使用具有不同构造函数的对象,即使它是 const by ref,使用类或结构,仍然会创建 Construct。例如:

DoSomething(const Construct1& constr1, const Construct2& constr2)
{
    constr1.x + constr2.t
}
DoSomething(Construct1(1, 2, 3), Construct2(4, 5, 6));

在这种情况下,Construct1 和 Construct2 都被创建了。

我想要的是:

DoSomething(Construct1(x, y, z), Construct2(t, u, p));
or
DoSomething(Construct1(x, y), Constrcut2(t, u, p, o));

在编译时展开为:

DoSomething(int x, int y, int z, int t, int u, int p);

从而消除了创建对象的需要。我不是在寻找对象解决方案。任何可以扩展它的东西都是受欢迎的。即使它是一个宏。我不是在寻找一个完整的解决方案,但如果您能指出我应该阅读的内容以便自己制作,那么这非常受欢迎。

提前致谢。

【问题讨论】:

  • 您的参数列表中有两个ys。
  • “我不想从包含数百万行的文件中读取值”是什么意思?

标签: c++ templates function macros


【解决方案1】:

重载是基于参数types 而不是参数names。您不能拥有具有相同类型的参数列表的重载函数。

【讨论】:

  • 那些名字只是为了迭代这两个函数具有相同数量和类型的参数但做不同的事情。
  • 我真的不明白你的问题是什么。评论让我很困惑。我不禁觉得你把这件事复杂化了。重载确实看起来不是问题的正确答案。我希望最好的解决方案涉及具有不同名称的函数,让任何阅读代码的人都清楚他们的工作,以及为什么具有相同参数列表的每个函数都是不同的。
  • @user985611 为什么不能使用不同的函数名?
【解决方案2】:

我认为你有几个误解。最明显的是参数的名称很重要......它们并不重要,就编译器而言,这两个函数声明声明了一个接受 6 个整数的函数(考虑一下,如果它们不同,@987654321 @做什么?)

第二个误解是对象的创建必然意味着分配。在您提供的代码中:DoSomething( Object1(x,y,z), Object2(t,y,u) ) 有两个对象,但没有一个动态分配(除非您在 Object1Object2 构造函数中执行它们)。

总体而言,您应该编写可读的代码,并且只有当证明很慢时,然后配置文件并尝试优化瓶颈。

【讨论】:

  • @user985611:您确实了解创建这些对象的成本几乎为零,并且您正在寻找一种强制更改代码的方法,这将使其更难理解,只是为了规避问题不存在?
  • 我不需要其他人来理解代码。除非您有解决方案,否则请不要仅仅为了发帖而发帖。如果我问,这意味着我需要它。
  • 你的要求很难完成,你将产生的代码也很难维护。您在问题中提供的原因要么不清楚,要么根本不正确:“避免不必要的内存分配” - 这不会发生。 “在不经过 Object1 和 Object2 的情况下使用 x、y、z、t、y、u”——在典型情况下,编译器会在后台执行此操作!编译器足够聪明,可以优化代码。但是,您提到了文件中的某些行,您是在尝试以某种方式序列化文件中的这些函数(或函数调用)还是什么?
  • 这些原因只是例子。我只想知道如何在不使用类或任何需要在运行时创建的东西的情况下让编译器区分两个相同的函数。
  • @user985611:你应该采取开放的学习方式。您已决定将答案阅读为对您的方法的咆哮,很好,但请注意,在许多情况下,接受答案中的方法会比原始版本更糟糕,其中 需要在运行时创建。如果您想知道原因,您需要了解当 const 引用绑定到临时文件时会发生什么。正如我在答案中已经提到的,这是您的误解之一。祝你好运。
【解决方案3】:

恐怕你得另寻路了。编译器会忽略您在函数声明中为参数指定的任何名称,因此就它所关心的而言,您所拥有的是:

DoSomething(int, int, int, int, int, int);

DoSomething(int, int, int, int, int, int);

由于它们之间没有区别,因此您根本没有声明两个重载函数——您只是声明了两次相同的函数。尝试使用相同的签名定义两个函数则违反了单一定义规则。

编辑:哦,我想我应该补充一点,如果没有返回类型,那些也不是允许的函数声明(不是说它与手头的问题有关,但以防万一有人决定对此感到迂腐——虽然我很难想象一个 C++ 程序员会做这样的事情)。

【讨论】:

    【解决方案4】:

    您可以通过让 Object1 和 Object2 公开底层存储 int 来避免不需要的副本

    struct Object1 {
    ...
    int x;
    int y;
    ...
    
    }
    
    //<--- passed by reference, no copy happens --->
    DoSomething( const Object1& o1, const Object2& o2 ) 
    {
      int somethingUseful = o1.x * o2.w - o1.y * o2.z;
    }
    

    如果您仍然觉得这种方法出现的副本并不真正需要,请详细说明。

    【讨论】:

    • 可能是快速且仍然“干净”的最佳方法。其他一切都没有直接进行内存操作,即。备忘录。 ;-) 不过,您可能会考虑不将您的 refs 设为 const(对于这种特殊情况)。
    • @Robin,对于 OP 描述的用例,引用必须是 const。临时对象只能绑定到 const refs,不能绑定到 non-const refs。
    • @Rob,是的……不。 ;-) 我的意思是吸气剂,即。 int&amp; getX() const; 当然,你对 o1 和 o2 是完全正确的,所以谢谢你的澄清!基本上,对于这个用例,我只需将 Object1 和 Object2 中的变量声明为 public 并直接处理它们,从而避免对 DoSomething() 中的整数进行任何复制操作。
    • 好点,刚刚删除了吸气剂并明确表示您可以从对象中复制内容
    • 明白了。这很有意义。谢谢你的回答。
    【解决方案5】:

    你甚至不能在 C++ 中定义两个相同的函数,所以如果假设它们确实存在,那么询问编译器如何区分这两者是没有意义的。

    然后您似乎在问如何在不需要额外分配的情况下传递对象。这是通过 const 引用完成的,但考虑到您甚至还没有固化程序的结构,因此担心这一点似乎还为时过早。首先编写您的程序,然后再在需要时进行优化。过早的优化是万恶之源。

    【讨论】:

    • 不要假设我知道多少或我想用它做什么。我问了一个问题,除非你知道答案,否则评论毫无意义。我不想创建对象。 const to ref 创建对象。
    • 通过 const ref 传递不会创建任何东西,但它确实需要对象存在于某处,是的。如果您根本不想创建对象,可能会问为什么您有一个包含这些对象的函数签名。如果将对象放在函数签名中,则无法绕过对象创建,尽管优化器可能会内联调用然后删除对象创建(假设它没有副作用)。
    • 我不是在寻找对象解决方案。任何可以扩展它的东西: DoSomething(Construct1(x, y, z), Construct2(t, y, u)) 到 DoSomething(x, y, z, t, y, u) 都是受欢迎的。不管它有多奇怪。
    • 这个问题没有意义。 “展开”是什么意思?是什么阻止您只使用DoSomething(x, y, z, t, y, u)?如果您不想要对象解决方案,请不要编写接受对象的函数。
    • 我有很多这样的功能,我不想使用不同的名字。我没有写对象函数。正如我所说,我希望构造只是为了帮助编译器区分这两个函数。 DoSomething(Construct1(1, 2, 3), Construct2(4, 5, 6)) 创建对象只是为了能够在具有相同类型和参数数量的多个函数之间进行选择是没有意义的。我不在乎担心它是否毫无意义。
    猜你喜欢
    • 2022-08-18
    • 2014-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多