C ++ 14variables模板:他们的目的是什么? 任何使用示例?
C ++ 14将允许创build模板化的variables。 通常的例子是一个variables“pi”,它可以被读取以得到各种types的math常数π的值( int
为3; float
为最可能的值)
除此之外,我们可以通过在模板化的结构或类中包装一个variables来实现这个function,这与types转换是如何结合的? 我看到一些重叠。
除了pi的例子之外,它是如何处理非constvariables的呢? 任何使用示例,了解如何充分利用此function以及它的目的是什么?
除了pi的例子之外,它是如何处理非constvariables的呢?
目前,它似乎为这个types分别实例化variables。 也就是说,你可以赋值10给n<int>
,这与模板定义不同。
template<typename T> T n = T(5); int main() { n<int> = 10; std::cout << n<int> << " "; // 10 std::cout << n<double> << " "; // 5 }
如果声明是const
,那么它是只读的。 如果它是一个constexpr
,就像所有的constexpr
声明一样,在constexpr
(ressions)之外没有多less用处。
除此之外,我们可以通过在模板化的结构或类中包装一个variables来实现这个function,这与混合types转换是如何结合的?
这意味着一个简单的build议。 我无法看出它是如何以显着的方式影响types转换的。 正如我已经说过的那样,variables的types是你实例化模板的types。 即, decltype(n<int>)
是int。 decltype((double)n<int>)
是double等等。
任何使用示例,了解如何充分利用此function以及它的目的是什么?
N3651提供了一个简洁的理由。
唉,现有的C ++规则不允许模板声明来声明一个variables。 有这个问题的众所周知的解决方法:
•使用类模板的constexpr静态数据成员
•使用constexpr函数模板返回所需的值
这些解决方法已经为数十年而闻名,并且有据可查。 标准类如std :: numeric_limits是典型的例子。 虽然这些解决方法并不完美,但是它们的缺点在一定程度上是可以忍受的,因为在C ++ 03时代,只有简单的内置types常量可以毫无限制地直接高效地支持编译时。 所有这一切都随着C ++ 11中的constexprvariables的采用而改变,这直接和有效地支持了用户定义types的常量。 现在,程序员正在使程序中的常量(类types)越来越明显。 因此,增加与解决方法相关的困惑和挫折。
…
“静态数据成员”的主要问题是:
•他们需要“重复”的声明:一旦进入课堂模板,一旦在课堂模板之外,提供“真正的”定义,以防止常规使用。
•由于提供两次相同的声明的必要性,程序员都感到困惑和困惑。 相比之下,“普通”常量声明不需要重复声明。
…
这个类别中的着名例子可能是numeric_limits的静态成员函数,或者是诸如
boost::constants::pi<T>()
等函数。Constexpr函数模板不会承受静态数据成员所具有的“重复声明”问题; 此外,他们提供function抽象。 但是,他们强迫程序员事先在定义站点select如何传递常量:通过const引用或简单的非引用types。 如果通过const引用传递,则常量必须在静态存储中被系统地分配; 如果通过非引用types,则常量需要复制。 复制对于内置types来说不是问题,但是对于用户定义types来说,它的价值语义并不仅仅是内build微型内置types(例如matrix,整数或大浮点等)的封装。相比之下,普通的“const(expr)variables不会遇到这个问题。 提供了一个简单的定义,常量是否需要在存储中进行布局的决定取决于使用情况,而不是定义。
我们可以通过在模板化的结构或类中包装一个variables来拥有这个特性
是的,但这将是无偿的语法盐。 对血压不健康。
pi<double>
传达的意图比pi<double>::value
更好。 简明扼要。 在我的书中,这足以说明和鼓励这种语法。
我想知道是否有可能:(假设可用的模板lambda)
void some_func() { template<typename T> std::map<int, T> storage; auto store = []<typename T>(int key, const T& value) { storage<T>[key] = value; }; store(0, 2); store(1, "Hello"s); store(2, 0.7); // All three values are stored in a different map, according to their type. }
现在,这有用吗?
作为一个简单的用法,请注意, pi<T>
的初始化使用显式转换(显式调用一元构造函数),而不是统一的初始化。 这意味着,给定一个具有构造函数radians(double)
的typesradians
,可以写pi<radians>
。
C ++ 14variables模板的另一个实际例子是当你需要一个函数来传递std::accumulate
:
template<typename T> T const & (*maxer) (T const &, T const &) = std::max<T>; std::accumulate(some.begin(), some.end(), initial, maxer<float>);
请注意,使用std::max<T>
是不够的,因为它不能推断确切的签名。 在这个特定的例子中,你可以使用max_element
来代替,但重点是有一整套函数共享这个行为。
那么,你可以用这个来编写这样的编译时间代码:
#include <iostream> template <int N> const int ctSquare = N*N; int main() { std::cout << ctSquare<7> << std::endl; }
这是相当于一个重大的改善
#include <iostream> template <int N> struct ctSquare { static const int value = N*N; }; int main() { std::cout << ctSquare<7>::value << std::endl; }
人们曾经写过在variables模板被引入之前执行模板元编程。 对于非types值,我们可以用C ++ 11和constexpr
做到这一点,所以模板variables的优点是允许基于types的variables模板进行计算。
TL; DR:他们不允许我们做任何我们以前做不到的事情,但是他们使模板元编程减less了PITA。