C++14 变量模板:它们的目的是什么?任何使用示例?

2021-12-13 00:00:00 templates c++ c++14 rationale

C++14 将允许创建模板化的变量.通常的例子是一个变量 'pi',它可以被读取以获得各种类型的数学常数 π 的值(int 为 3;float 可能是最接近的值等)

C++14 will allow the creation of variables that are templated. The usual example is a variable 'pi' that can be read to get the value of the mathematical constant π for various types (3 for int; the closest value possible with float, etc.)

除了我们可以通过将变量包装在模板化结构或类中来拥有此功能之外,这如何与类型转换混合?我看到一些重叠.

Besides that we can have this feature just by wrapping a variable within a templated struct or class, how does this mix with type conversions? I see some overlapping.

除了 pi 示例之外,它如何处理非常量变量?任何使用示例来了解如何充分利用此类功能及其目的是什么?

And other than the pi example, how would it work with non-const variables? Any usage example to understand how to make the most of such a feature and what its purpose is?

推荐答案

除了 pi 示例之外,它如何与非常量一起使用变量?

And other than the pi example, how would it work with non-const variables?

目前,它似乎为类型单独实例化变量.即,您可以将 10 分配给 n,这将与模板定义不同.

Currently, it seems to instantiate the variables separately for the type. i.e., you could assign 10 to n<int> and it would be different from the template definition.

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(resions) 之外没有太多用处.

If the declaration is const, it is readonly. If it's a constexpr, like all constexpr declarations, it has not much use outside constexpr(ressions).

此外我们可以通过包装一个变量来拥有这个功能在模板化结构或类中,它如何与类型混合转化?

Besides that we can have this feature just by wrapping a variable within a templated struct or class, how does this mix with type conversions?

这是一个简单的提议.我无法看到它如何以重要的方式影响类型转换.正如我已经说过的,变量的类型是您实例化模板的类型.即,decltype(n) 是 int.decltype((double)n) 是 double 等等.

It's meant to be a simple proposal. I am unable to see how it affects type conversions in a significant way. As I already stated, the type of the variable is the type you instantiated the template with. i.e., decltype(n<int>) is int. decltype((double)n<int>) is double and so on.

了解如何充分利用此类功能的任何用法示例它的目的是什么?

Any usage example to understand how to make the most of such a feature and what its purpose is?

N3651 提供了一个简洁的理由.

N3651 provides a succinct rationale.

唉,现有的 C++ 规则不允许模板声明声明一个变量.对此有众所周知的解决方法问题:

Alas, existing C++ rules do not allow a template declaration to declare a variable. There are well known workarounds for this problem:

? 使用类模板的 constexpr 静态数据成员

? use constexpr static data members of class templates

? 使用返回所需值的 constexpr 函数模板

? use constexpr function templates returning the desired values

这些变通方法已为人所知数十年并且有据可查.标准类如 std::numeric_limits 是原型例子.尽管这些变通方法并不完美,但它们的缺点在某种程度上是可以忍受的,因为在 C++03 时代只是简单,内置类型常量享有不受约束的直接和高效编译时支持.所有这一切都随着采用C++11中的constexpr变量,扩展了直接高效支持用户定义类型的常量.现在,程序员使(类类型的)常量在程序中越来越明显.因此,与此相关的困惑和挫折越来越大解决方法.

These workarounds have been known for decades and well documented. Standard classes such as std::numeric_limits are archetypical examples. Although these workarounds aren’t perfect, their drawbacks were tolerable to some degree because in the C++03 era only simple, builtin types constants enjoyed unfettered direct and efficient compile time support. All of that changed with the adoption of constexpr variables in C++11, which extended the direct and efficient support to constants of user-defined types. Now, programmers are making constants (of class types) more and more apparent in programs. So grow the confusion and frustrations associated with the workarounds.

...

静态数据成员"的主要问题是:

The main problems with "static data member" are:

? 它们需要重复"声明:一旦在类中模板,一旦在类模板之外提供真实"使用 odr 时的定义.

? they require "duplicate" declarations: once inside the class template, once outside the class template to provide the "real" definition in case the con- stants is odr-used.

? 程序员对提供两倍相同的内容的必要性感到恼火和困惑宣言.相比之下,普通"常量声明不需要重复声明.

? programmers are both miffed and confused by the necessity of providing twice the same declaration. By contrast, "ordinary" constant declarations do not need duplicate declarations.

...

这个类别中众所周知的例子可能是静态成员numeric_limits 的函数,或诸如boost::constants::pi() 等 Constexpr 函数模板没有遭受静态数据成员的重复声明"问题有;此外,它们提供功能抽象.然而,他们强制程序员提前选择,在定义站点,如何常量将被传递:要么通过一个常量引用,要么通过普通的非引用类型.如果通过 const 引用传递,则常量必须系统地分配在静态存储中;如果通过非引用类型,则常量需要复制.复制不是内置类型的一个问题,但它是用户定义的一个showstopper具有值语义的类型不仅仅是 tiny 的包装器内置类型(例如矩阵、整数或 bigfloat 等)相比之下,普通" const(expr) 变量不受此影响问题.提供了一个简单的定义,并决定了常量是否实际上只需要在存储中进行布局取决于用法,而不是定义.

Well known examples in this category are probably static member functions of numeric_limits, or functions such as boost::constants::pi<T>(), etc. Constexpr functions templates do not suffer the "duplicate declarations" issue that static data members have; furthermore, they provide functional abstraction. However, they force the programmer to chose in advance, at the definition site, how the constants are to be delivered: either by a const reference, or by plain non- reference type. If delivered by const reference then the constants must be systematically be allocated in static storage; if by non-reference type, then the constants need copying. Copying isn’t an issue for builtin types, but it is a showstopper for user-defined types with value semantics that aren’t just wrappers around tiny builtin types (e.g. matrix, or integer, or bigfloat, etc.) By contrast, "ordinary" const(expr) variables do not suffer from this problem. A simple definition is provided, and the decision of whether the constants actually needs to be layout out in storage only depends on the usage, not the definition.

相关文章