是T Min(T,T);总是优于const T& Min(const T&,const T&);如果sizeof(T)< = sizeof(void *)?

时间:2014-02-20 07:31:17

标签: c++ performance templates overloading overload-resolution

template<class T>
T Min(T a, T b)
{
    return a < b ? a : b;
}

template<class T>
const T& Min(const &T a, const T& b)
{
    return a < b ? a : b;
}

哪个更好?或者,我应该按如下方式重新定义模板函数:

template<class T, ENABLE_IF(sizeof(T) <= sizeof(void*))>
T Min(T a, T b)
{
    return a < b ? a : b;
}

template<class T, ENABLE_IF(sizeof(T) > sizeof(void*))>
const T& Min(const &T a, const T& b)
{
    return a < b ? a : b;
}

// Note: ENABLE_IF is a helper macro.

2 个答案:

答案 0 :(得分:3)

我不能肯定地说,但鉴于此

template<class T>
const T& Min(const &T a, const T& b)
{
    return a < b ? a : b;
}

..基本上被替换为(比如T = bool):

const bool & Min(const bool & a, const bool & b)
{
    return a < b ? a : b;
}

我想说这是一个公平的假设,编译器会以最有效的方式传递bool。 I.E,只是因为我们正在使用&amp;并不意味着 通过引用传递。

另外几个想法: 调用函数时,参数被压入堆栈,或者它们通过寄存器传递。

的唯一方法
bool Min(bool a, bool b)
{
    return a < b ? a : b;
}

会比

“更好”/“更快”
const bool & Min(const bool & a, const bool & b)
{
    return a < b ? a : b;
}

是否传递bool比传递const bool &更快(忽略函数开头的解除引用)。我不能看到这是真的,因为除非它被推入堆栈(取决于你的调用约定),寄存器至少都是主机架构上指针的大小。 (I.E,rax是64位,eax是32位)

此外,我认为编译器内联更容易,因为(仅从函数签名)我们可以保证函数永远不会在本地修改ab的值,因此不需要空间。

对于用户定义的类型,有两种情况。

  1. 该类型适合寄存器,我们可以将其视为基本类型。
  2. 该类型不适合注册表,必须通过引用传递(如果我们使用const & T)或作为副本传递(如果我们仅使用T)。由于复制类会调用类构造函数,因此const & T在每种情况下都可能更快。
  3. 但是,我真的只是在这里猜测。要检查boolconst bool &之间是否存在差异,最好的方法是通过输出程序集并查看是否存在任何差异来检查您的特定编译器。

    HTH。

答案 1 :(得分:2)

我已经看到g ++在优化时自动执行此操作:它可以生成Min的版本,当它可以告诉您这样做更有效并且不会违反时,可以按值获取参数 rule(我认为基本上是指带有普通复制构造函数的小类)。

我不知道这个优化的名称是什么,或者其他编译器是否实现了它。


顺便说一句,我想知道你是否可以在C ++ 11中获得两全其美:

template <typename T, typename U>
constexpr auto Min(T&& l, U&& r) -> decltype(l < r ? l : r)
{
    return l < r ? l : r;
}

如果我对“通用引用”的理解是正确的,那么这应该不如在示例中使用左值引用那么低效,如果lr是rvalues,则可能更有效(例如整数文字)。作为一个额外的好处,你可以比较不同类型的东西(int vs long或者你有什么)。