C++ 重载运算符正文只包含一个函数调用

C++ 重载运算符正文只包含一个函数调用,c++,c++11,C++,C++11,我有这个功能 int add(T a, T b) { return a.blah +b.blah; } 我想重载plus操作符,我必须选择(当然,在这种情况下,plus操作符已经完成了下面代码所做的事情) 选项1: int operator+(T lhs, T rhs) { return add(a,b); } int operator+(T lhs, T rhs) { return a.blah+b.blah; } 选项2: int operator+(T lhs, T rh

我有这个功能

int add(T a, T b)
{
  return a.blah +b.blah;
}
我想重载plus操作符,我必须选择(当然,在这种情况下,plus操作符已经完成了下面代码所做的事情)

选项1:

int operator+(T lhs, T rhs)
{
  return add(a,b);
}
int operator+(T lhs, T rhs)
{
  return a.blah+b.blah;
}
选项2:

int operator+(T lhs, T rhs)
{
  return add(a,b);
}
int operator+(T lhs, T rhs)
{
  return a.blah+b.blah;
}

这些定义中有没有一个比另一个有性能优势?需要注意的是,我尝试实现的函数对STL容器的元素执行更复杂的操作。

使用选项1,不要重复。确保编译器在定义运算符+时看到add的定义,以便它可以内联代码。当打开优化时,生成的代码将完全没有区别

struct T
{
    int blah;
};

int add(T a, T b)
{
  return a.blah +b.blah;
}

int operator+(T lhs, T rhs)
{
  return add(lhs, rhs);
}
GCC生成:

add(T, T):
  lea eax, [rdi+rsi]
  ret
operator+(T, T):
  lea eax, [rsi+rdi]
  ret

Clang和Microsoft编译器生成相同的代码

如果代码比较复杂,编译器拒绝内联<代码>添加<代码> > <代码>操作符+< />代码>,请考虑生成运算符+内联函数。然后它将被内联,因为它只执行一个调用,调用方将直接调用
add
,而不需要额外的开销


通常的警告:当然,您应该一如既往地进行基准测试,以查看是否存在任何真正的差异,并查看造成差异的原因,同时查看生成的代码以检查优化是否按预期执行:-)

使用选项1,不要重复您自己的操作。确保编译器在定义运算符+时看到add的定义,以便它可以内联代码。当打开优化时,生成的代码将完全没有区别

struct T
{
    int blah;
};

int add(T a, T b)
{
  return a.blah +b.blah;
}

int operator+(T lhs, T rhs)
{
  return add(lhs, rhs);
}
GCC生成:

add(T, T):
  lea eax, [rdi+rsi]
  ret
operator+(T, T):
  lea eax, [rsi+rdi]
  ret

Clang和Microsoft编译器生成相同的代码

如果代码比较复杂,编译器拒绝内联<代码>添加<代码> > <代码>操作符+< />代码>,请考虑生成运算符+内联函数。然后它将被内联,因为它只执行一个调用,调用方将直接调用
add
,而不需要额外的开销


通常的警告:当然,您应该一如既往地进行基准测试,以查看是否存在任何真正的差异,并查看造成差异的原因,还应查看生成的代码,以检查是否按照预期执行了优化:-)

选项1更好,因为您没有重复代码


通过常量引用传递T可能更好,以避免值复制。

选项1更好,因为您没有复制代码


通过常量引用传递T可能更好,以避免值复制。

如果可以这样做,那么选项2不是一个选项,因为它将是一个无限递归调用。不要使用内置类型进行说明。那太令人困惑了。改为使用枚举。然后,当与问题结合时,代码将有意义。在充分优化flag.DRY并使用选项1后,2可能会在同一代码中编译,尤其是当它是一个更复杂的操作时。如果你关心性能和对象可能很大,考虑将它们传递为<代码> const t/< /COD>。一些建议:不要担心优化每一行代码。编写的代码自然易懂。在和概要文件上进行优化的编译。如果性能可以接受,那么您的测试就完成了。你会惊讶于现在编译器能优化多少,尤其是在代码不晦涩的情况下。如果你能做到这一点,那么选项2就不是一个选项,因为它将是一个无限递归调用。不要为了说明的目的而使用内置类型。那太令人困惑了。改为使用枚举。然后,当与问题结合时,代码将有意义。在充分优化flag.DRY并使用选项1后,2可能会在同一代码中编译,尤其是当它是一个更复杂的操作时。如果你关心性能和对象可能很大,考虑将它们传递为<代码> const t/< /COD>。一些建议:不要担心优化每一行代码。编写的代码自然易懂。在和概要文件上进行优化的编译。如果性能可以接受,那么您的测试就完成了。你会惊讶于现在编译器能优化多少,特别是如果代码不是晦涩难懂的话。