【问题标题】:Non-type template parameters非类型模板参数
【发布时间】:2011-08-06 22:47:42
【问题描述】:

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

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

我了解常量积分表达式是什么。上面的 sn-p 中不允许像 std::string 这样的非常量类型的原因是什么?

【问题讨论】:

  • 一个模板参数在编译时被解析。

标签: c++ templates


【解决方案1】:

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

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

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

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

【讨论】:

  • @ALOToverflow:属于“指向成员的指针”。它要么是“指向成员函数的指针”,要么是“指向成员数据的指针”。
  • 值得注意的是,对于指向对象(或实例字段)的指针的情况,对象必须具有静态存储时长和链接(C++ 11之前为外部,C++11中为内部或外部) ),以便可以在编译时创建指向它们的指针。
  • 在 C++20 中,现在允许这样做,前提是该类型具有强结构化相等性、是文字、没有可变/易失性子对象并且太空船运算符是公共的。
  • 类型是否可以是非类型模板参数与运行时改变事物的问题是正交的; int 变量可以改变,但int NTTP 不能。
【解决方案2】:

这是不允许的。

但是,这是允许的:

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

【讨论】:

  • @Mahesh:因为模板的基本模板是std::string 指针或引用对象的地址。如果该变量是本地变量,那么每次调用该函数时,您可能会得到不同的地址。
  • @Mahesh:你不知道编译时调用堆栈是什么样的。在您的函数之前,可能已经调用了 10 个其他或 3 个其他或许多其他,因此堆栈上创建字符串的地址可能会因调用而异。当你有一个带有外部链接的对象时,它的地址在编译/链接期间是固定的。
  • @Xeo "它的地址在编译/链接期间是固定的。" 或者不是,对于可重定位或位置无关的代码。
  • 这个答案(目前)似乎没有解决 OP 的问题,即问 为什么 这种行为存在;这个答案只是重申了 OP 的例子,没有提供任何解释。
  • 聚会迟到了,看来智能指针也不起作用
【解决方案3】:

你需要能够修改模板参数

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

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

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

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


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

【讨论】:

  • 我们现在有一些非常像你描述的东西;你想编辑这个答案,因为它已经是正确的吗?
  • @Davis 由于我对类类型模板参数的经验不够,欢迎您添加相关更改。
  • @Davis 我添加了一些文字。如果您检查不准确,将不胜感激!
  • 感谢更新;我稍微清理了一下。
【解决方案4】:

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

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

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

【讨论】:

  • 你引用了一个引用,那么来源是什么?如果它有报价来源,我想投票赞成。
猜你喜欢
  • 2021-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-03
  • 2019-04-24
相关资源
最近更新 更多