我观看了演讲并阅读了博客文章,但我仍然不确定...为什么
template<bool B> struct conditional { template<class T, class F> using f = T; };
template<> struct conditional<false> { template<class T, class F> using f = F; };
template<bool B, class T, class F> using conditional_t = typename conditional<B>::template f<T, F>;
比编译更快
template<bool B, class T, class F> struct conditional { using type = T; };
template<class T, class F> struct conditional<false, T, F> { using type = F; };
template<bool B, class T, class F> using conditional_t = typename conditional<B, T, F>::type;
?
第一个版本需要实例化一个带有一个参数的模板类和一个带有两个参数的模板别名,第二个版本需要实例化一个具有三个参数的模板类和一个带有零的模板别名...好的,模板别名要便宜一些,但这有很大的不同吗?
答案 0 :(得分:2)
首先,我认为有一点不同:
template<bool B, class T, class F> struct conditional;
template<class T, class F> struct conditional<false, T, F>;
此处的编译器必须针对false, T, F
对所有3个参数进行模式匹配。现在,这很容易,但不是免费的。
template<bool B> struct conditional;
template<> struct conditional<false>;
在这里它必须与false
的模式匹配一个参数。
因此严格挑选专业是容易的。
接下来的事情是生成的类型的长度;我发现长类型名称导致编译器内存使用变得讨厌。在非SCARY情况下,conditional<b, T, F>
是实际唯一和不同类型的名称。其长度为参数长度的O(n)。
在SCARY情况下,不会创建新的O(n)类型。
typename conditional<false>::template f<T, F>;
这只是F
的别称。类型conditional<false>
已创建,其中具有别名模板,并且该别名模板未创建新类型。返回类型为F
,如果您尝试将其与template<class,class>class Z, class A, class B, Z<A,B>
匹配,则它将不匹配。
最后也是最重要的是记忆。每次对SCARY条件的调用都会创建conditional<false>
或conditional<true>
。因此,第500次,它可以进行零模板特化检查,而只需获取预先计算的类型即可。
从该预先计算的类型中,我们获得template type<T,F>
别名;我们将其应用而无需记住即可获得T
或F
。
在非SCARY中,每个不同的T
和F
表示不同的conditional<b,T,F>
类型。因此,更大的备忘缓存,更少的匹配数以及未命中的情况,您需要运行完整的模板专业化检查,以确保没有人去
template<class U> conditional<true, int, U>{using type=U;};
并针对您正在使用的特定类型覆盖它。