【问题标题】:Void pointer as template argument in C++void 指针作为 C++ 中的模板参数
【发布时间】:2016-01-11 12:08:42
【问题描述】:

以下内容无法编译:

template<void *p>
class X {
// ...
};

int r;

int main()
{
    X<&r> x;

    return 0;
}

错误信息是

x.cc:10:6: 错误:无法将模板参数‘& r’转换为‘void*’

将 &r 显式转换为 (void *) 也无济于事。错误信息变为:

x.cc:10:14: 错误:无法将模板参数‘(void*)(& r)’转换为‘void*’

标准的哪一部分规定了这种行为? GCC 版本是gcc version 5.2.1 20151003 (Ubuntu 5.2.1-21ubuntu2)

编辑:

请注意,使用例如int * 而不是 void * 按预期工作。

编辑:(回答我自己)

当指定 -std=c++1z 时,它gcc HEAD 6.0.0 20151016 (experimental) 一起工作,无论是隐式还是显式转换为“无效*”。

确实clang HEAD 3.8.0 (trunk 250513) 一起工作,并且从(至少)clang 3.6.0 (tags/RELEASE_360/ final) 在指定 --std=c++1z 并显式转换为 *void *" 时。 如果没有明确的演员表,clang 会抱怨如下:

x.cc:10:7: 错误:在转换后的常量表达式中不允许从“int *”转换为“void *”

c++ 语言规范中修复这个 bug 的责任是 N4268,clang 已经实现了。

【问题讨论】:

  • 我不明白这怎么可能是上述问题的重复。这完全是关于使用“void *”作为模板参数,另一个是关于使用“const char *”作为模板参数。
  • 从技术上讲,[temp.param]/p4 禁止使用 void* 作为模板非类型参数,尽管我所知道的主要编译器实际上没有强制执行此禁止甚至发出诊断。
  • 好的,这很有趣。您指的是哪个文件?

标签: c++ templates gcc standards void


【解决方案1】:

通常,任何指向void* 的指针都允许进行转换。

[C++11, 4.10/2] “指向 cv T 的指针”类型的纯右值,其中 T 是 对象类型,可以转换为“指向 cv 的指针”类型的纯右值 空白”。将“指向 cv T 的指针”转换为“指向 cv void”指向对象所在的存储位置的开始 T 类型的驻留,就好像该对象是最派生的对象(1.8) 类型 T(即,不是基类子对象)。空指针值 转换为目标类型的空指针值。

但是,对于非类型模板参数,指定了某些转换:

[C++11, 14.3.2/5] 对每个都执行以下转换 表达式用作非类型模板参数。如果非类型 模板参数不能转换为对应的类型 模板参数,那么程序格式错误。

[...]

——对于指向对象的类型指针的非类型模板参数, 限定转换 (4.4) 和数组到指针的转换 (4.2) 适用;如果模板参数是 std::nullptr_t 类型, 应用了空指针转换(4.10)。 [...]

通过省略,我们可以推断根本不允许这种转换。

【讨论】:

  • 我想不出这种不一致的任何原因。对我来说,这是一个错误。
【解决方案2】:

我不能引用我脑海中的章节和诗句(欢迎编辑),但你试图做的事情在 c++ 中是不允许的。

模板参数必须在编译时已知。指针仅在链接时解析,除非:

  1. 在模板参数列表中默认使用= nullptr

  2. 它们是成员函数指针(在编译时是已知的,因为它们只是偏移量)。

例如,这将编译:

template<void * = nullptr>
class X {
    // ...
};

int r;

int main()
{
    X<nullptr> x;

    return 0;
}

【讨论】:

  • 不,将“void *”替换为“int *”,代码示例就可以编译了。
  • 我只想补充一点,当将它与类型特征等一起使用时,语法不容易弄清楚。这是一个如何将它与 std::enable_if 一起使用的示例:template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 4, T&gt;::type* = nullptr&gt; void do_if_ptrs_are_32bit(void * p) {}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 2015-03-16
  • 2021-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多