c++ 模板参数的地址可以用于示例化另一个模板吗?

bksxznpy  于 2023-06-25  发布在  其他
关注(0)|答案(2)|浏览(143)

我在某个地方读到一个技巧,如何将常量文字值转换为静态变量(这在模板中可能很有用)。看看我的示例代码中的makeStatic函数,它可以做到这一点。
我尝试使用makeStatic的结果来调用makeStatic

  1. template <auto VALUE>
  2. consteval const auto &makeStatic() {
  3. return VALUE;
  4. }
  5. struct Foo {
  6. };
  7. struct Bar {
  8. const Foo *x;
  9. };
  10. Foo foo;
  11. int main() {
  12. constexpr Bar bar{&makeStatic<Foo{}>()};
  13. // constexpr Bar bar{&foo};
  14. makeStatic<bar>();
  15. }

这个例子是由clang和MSVC编译的,但是gcc拒绝了它(godbolt):

  1. <source>: In function 'int main()':
  2. <source>:19:20: error: no matching function for call to 'makeStatic<bar>()'
  3. 19 | makeStatic<bar>();
  4. | ~~~~~~~~~~~~~~~^~
  5. <source>:2:23: note: candidate: 'template<auto VALUE> consteval const auto& makeStatic()'
  6. 2 | consteval const auto &makeStatic() {
  7. | ^~~~~~~~~~
  8. <source>:2:23: note: template argument deduction/substitution failed:
  9. <source>:19:20: error: the address of 'Foo()' is not a valid template argument
  10. 19 | makeStatic<bar>();
  11. | ~~~~~~~~~~~~~~~^~

哪个编译器是正确的?
注意:如果使用另一个bar定义,它使用一个全局变量来初始化bar,那么gcc将编译代码。
更新:我发现了一个类似的bug report in gcc's bugzilla,所以看起来这是一个gcc错误。我仍然想知道标准在哪里保证我的代码是格式良好的。

7jmck4yq

7jmck4yq1#

以下是模板参数([temp.arg.nontype]p3)的指针/引用对象/子对象中不允许的内容的完整列表:
对于引用或指针类型的非类型 * 模板-参数 *,或者对于类类型或其子对象的非类型 * 模板-参数 * 中的每个非静态数据成员或引用或指针类型,引用或指针值不应(分别)引用或作为地址:

  • 临时对象([class.temporary])
  • 字符串文字对象([lex.string])
  • typeid表达式的结果([expr.typeid])
  • 预定义的__func__变量([dcl.fct.def.general]),或
  • 上述一个的子对象([intro.object])。

模板参数对象不是临时对象,因为它从来不是prvalue([class.temporary]p1):
创建临时对象

  • 当prvalue被转换为xvalue([conv.rval])时,
  • 当实现需要传递或返回普通可复制类型的对象时(见下文),以及
  • 当抛出异常时([except.throw])。

而且它绝对不是一个字符串文本对象/typeid表达式/__func__/子对象的结果,所以应该接受它。

展开查看全部
lbsnaicq

lbsnaicq2#

这是一个GCC bug;模板参数对象的地址(该对象只存在于类类型的模板参数中!)当然是一个常量表达式,可以用作另一个模板参数。模板参数对象被明确提到在常量表达式中可用([expr.const]/4.5)。

相关问题