为什么我不能使用 std::string 作为非类型模板参数?

发布于 2024-11-01 22:46:18 字数 298 浏览 1 评论 0原文

我理解非类型模板参数应该是常量整数表达式。有人可以解释为什么会这样吗?

template <std::string temp>
void foo()
{
     // ...
}
错误 C2993:“std::string”:非类型模板参数“temp”的类型非法。

我明白什么是常数积分表达式。不允许像上面代码片段中的 std::string 这样的非常量类型的原因是什么?

I understand that non-type template parameters should be a constant integral expression. Can someone shed light why this is so?

template <std::string temp>
void foo()
{
     // ...
}
error C2993: 'std::string' : illegal type for non-type template parameter 'temp'.

I understand what a constant integral expression is. What are the reasons for not allowing non-constant types like std::string as in the above snippet ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

°如果伤别离去 2024-11-08 22:46:18

不能这样做的原因是因为在编译时无法解析和替换非常量表达式。它们可能在运行时发生变化,这需要在运行时生成新模板,这是不可能的,因为模板是一个编译时概念。

以下是标准允许的非类型模板参数 (14.1 [temp.param] p4):

非类型模板参数应具有以下类型之一(可选 cv 限定):

  • 整数或枚举类型,
  • 指向对象的指针或指向函数的指针,
  • 对对象的左值引用或对函数的左值引用,
  • 指向成员的指针,
  • std::nullptr_t

The reason you can't do this is because non-constant expressions can't be parsed and substituted during compile-time. They could change during runtime, which would require the generation of a new template during runtime, which isn't possible because templates are a compile-time concept.

Here's what the standard allows for non-type template parameters (14.1 [temp.param] p4):

A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

  • integral or enumeration type,
  • pointer to object or pointer to function,
  • lvalue reference to object or lvalue reference to function,
  • pointer to member,
  • std::nullptr_t.
过去的过去 2024-11-08 22:46:18

这是不允许的。

但是,这是允许的:

template <std::string * temp> //pointer to object
void f();

template <std::string & temp> //reference to object
void g();

请参阅 C++ 标准 (2003) 中的 §14.1/6,7,8。


插图:

template <std::string * temp> //pointer to object
void f()
{
   cout << *temp << endl;
}

template <std::string & temp> //reference to object
void g()
{
     cout << temp << endl;
     temp += "...appended some string";
}

std::string s; //must not be local as it must have external linkage!

int main() {
        s = "can assign values locally";
        f<&s>();
        g<s>();
        cout << s << endl;
        return 0;
}

输出:

can assign values locally
can assign values locally
can assign values locally...appended some string

That is not allowed.

However, this is allowed:

template <std::string * temp> //pointer to object
void f();

template <std::string & temp> //reference to object
void g();

See §14.1/6,7,8 in C++ Standard (2003).


Illustration:

template <std::string * temp> //pointer to object
void f()
{
   cout << *temp << endl;
}

template <std::string & temp> //reference to object
void g()
{
     cout << temp << endl;
     temp += "...appended some string";
}

std::string s; //must not be local as it must have external linkage!

int main() {
        s = "can assign values locally";
        f<&s>();
        g<s>();
        cout << s << endl;
        return 0;
}

Output:

can assign values locally
can assign values locally
can assign values locally...appended some string
心奴独伤 2024-11-08 22:46:18

您需要能够修改模板参数

template <std::string temp>
void f() {
 // ...
}

f<"foo">();
f<"foo">(); // same function?

现在,一个 impl 需要为 std::string 或任何其他任意用户定义的类提供唯一的字符序列,存储一个特定的值,其含义对于实现来说是未知的。此外,任意类对象的值无法在编译时计算。

计划考虑允许文字类类型作为 C++0x 之后的模板参数类型(见下文),它们由常量表达式初始化。可以通过根据数据成员的值递归地破坏这些数据成员来破坏它们(例如,对于基类,我们可以应用深度优先、从左到右的遍历)。但它绝对不适用于任意类。


C++20开始,我们现在可以使用结构类类型作为模板参数。简而言之,结构类必须有 constexpr 构造函数、析构函数,并且只有结构类型成员和基类(如标量、数组或引用)。它们还必须仅具有公共且非可变的基类和成员。这些规定,如果使用转换为参数类型的常量表达式实例化模板,则允许编译器有意义地修改参数。

You need to be able to mangle template arguments

template <std::string temp>
void f() {
 // ...
}

f<"foo">();
f<"foo">(); // same function?

Now an impl would need to come up with a unique sequence of characters for a std::string or, for that matter, any other arbitrary user defined class, storing a particular value, the meaning of which is not known to the implementation. And in addition, the value of arbitrary class objects can't be calculated at compile time.

It's planned to consider allowing literal class types as template parameter types for post-C++0x (see below), which are initialized by constant expressions. Those could be mangled by having the data members recursively mangled according to their values (for base classes, for example we can apply depth-first, left-to-right traversal). But it's definitely not going to work for arbitrary classes.


As of C++20, we are now allowed to use structural class types as template parameters. In a nutshell, structural classes must have a constexpr constructor, destructor and only structural-type members and base classes (like scalars, arrays thereof or references). They must also only have public and non-mutable base classes and members. These provisions, if the template is instantiated with a constant expression converted to the parameter type, allow the compiler to mangle the argument meaningfully.

筱武穆 2024-11-08 22:46:18

模板参数列表中提供的非类型模板参数是一个表达式,其值可以在编译时确定。这些论据必须是:

常量表达式,地址
具有外部功能或对象
链接,或静态类的地址
成员。

此外,字符串文字是具有内部链接的对象,因此您不能将它们用作模板参数。您也不能使用全局指针。考虑到明显可能出现舍入错误,所以不允许使用浮点文字。

A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be:

constant expressions, addresses of
functions or objects with external
linkage, or addresses of static class
members.

Also, string literals are objects with internal linkage, so you can't use them as template arguments. You cannot use a global pointer, either. Floating-point literals are not allowed, given the obvious possibility of rounding-off errors.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文