假设我有以下元函数:
template <typename T>
struct make_pair {
using type = std::pair<
typename std::remove_reference<T>::type,
typename std::remove_reference<T>::type
>;
};
它会改善编译速度吗(或其他东西)吗?
template <typename T>
struct make_pair {
using without_reference = typename std::remove_reference<T>::type;
using type = std::pair<without_reference, without_reference>;
};
我看到两种可能性:
每次看到typename std::remove_reference<T>::type
时,编译器都必须做一些工作。使用中间别名具有某种“缓存”行为,这使得编译器只能执行一次工作。
编译时性能是根据编译器必须执行的模板实例的数量来衡量的。因为std::remove_reference<T>::type
引用与std::remove_reference<T>::type
相同的类型,所以在这两种情况下只需要一个模板实例化,因此两个实现都是等效的WRT编译时性能。
我认为B是对的,但我想确定。如果答案结果是编译器特定的,我最感兴趣的是知道Clang和GCC的答案。
修改:
我对测试程序的编译进行了基准测试,以便使用一些数据。测试程序做了类似的事情:
template <typename ...> struct result;
template <typename T>
struct with_cache {
using without_reference = typename std::remove_reference<T>::type;
using type = result<without_reference, ..., without_reference>;
};
template <typename T>
struct without_cache {
using type = result<
typename std::remove_reference<T>::type,
...,
typename std::remove_reference<T>::type
>;
{ };
using Result = with[out]_cache<int>::type;
这些是10个程序编译的平均时间,result<>
中有10 000个模板参数。
-------------------------
| g++ 4.8 | clang++ 3.2 |
-----------------------------------------
| with cache | 0.1628s | 0.3036s |
-----------------------------------------
| without cache | 0.1573s | 0.3785s |
-----------------------------------------
测试程序由可用脚本here生成。
答案 0 :(得分:2)
我不能说所有编译器都是如此,但GCC,很可能是所有其他主要的编译器,都会使用memoization。如果你考虑一下,它几乎必须这样做。
考虑以下代码
&f<X, Y>::some_value == &f<X, Y>::some_value
这必须是真的,因此编译器必须确保它不会复制方法和静态成员的定义。现在可能有其他方法可以做到这一点,但这只是给我带来了回忆!我没有看到另一种方法来实现这一点(授予,我已经非常努力地考虑过了)
当我使用TMP时,我希望发生记忆。如果它没有,那将是一个真正的痛苦,太慢。我看到编译时性能的主要差异的唯一方法是:a)使用像Clang这样的更快的编译器(比GCC快3倍)并选择不同的算法。在我看来,TMP中的小常数因素在我的经验中比在C或C ++中更重要。选择正确的算法,尝试不做不必要的工作,尝试保持实例化的数量,并使用一个好的编译器(MSVC ++ 真的慢,远离C ++ 11合规,但GCC和Clang是相当不错);这就是你能做的一切。
此外,您应该总是牺牲编译时间来获得更好的代码。过早的编译时间优化比简单的过早优化更加邪恶。如果由于某种原因,性能变得严重不允许开发,可能会有一个例外;然而,我从来没有听说过这种情况。