我在某个地方读到一个技巧,如何将常量文字值转换为静态变量(这在模板中可能很有用)。看看我的示例代码中的makeStatic
函数,它可以做到这一点。
我尝试使用makeStatic
的结果来调用makeStatic
:
template <auto VALUE>
consteval const auto &makeStatic() {
return VALUE;
}
struct Foo {
};
struct Bar {
const Foo *x;
};
Foo foo;
int main() {
constexpr Bar bar{&makeStatic<Foo{}>()};
// constexpr Bar bar{&foo};
makeStatic<bar>();
}
这个例子是由clang和MSVC编译的,但是gcc拒绝了它(godbolt):
<source>: In function 'int main()':
<source>:19:20: error: no matching function for call to 'makeStatic<bar>()'
19 | makeStatic<bar>();
| ~~~~~~~~~~~~~~~^~
<source>:2:23: note: candidate: 'template<auto VALUE> consteval const auto& makeStatic()'
2 | consteval const auto &makeStatic() {
| ^~~~~~~~~~
<source>:2:23: note: template argument deduction/substitution failed:
<source>:19:20: error: the address of 'Foo()' is not a valid template argument
19 | makeStatic<bar>();
| ~~~~~~~~~~~~~~~^~
哪个编译器是正确的?
注意:如果使用另一个bar
定义,它使用一个全局变量来初始化bar
,那么gcc将编译代码。
更新:我发现了一个类似的bug report in gcc's bugzilla,所以看起来这是一个gcc错误。我仍然想知道标准在哪里保证我的代码是格式良好的。
2条答案
按热度按时间7jmck4yq1#
以下是模板参数([temp.arg.nontype]p3)的指针/引用对象/子对象中不允许的内容的完整列表:
对于引用或指针类型的非类型 * 模板-参数 *,或者对于类类型或其子对象的非类型 * 模板-参数 * 中的每个非静态数据成员或引用或指针类型,引用或指针值不应(分别)引用或作为地址:
typeid
表达式的结果([expr.typeid])__func__
变量([dcl.fct.def.general]),或模板参数对象不是临时对象,因为它从来不是prvalue([class.temporary]p1):
创建临时对象
而且它绝对不是一个字符串文本对象/
typeid
表达式/__func__
/子对象的结果,所以应该接受它。lbsnaicq2#
这是一个GCC bug;模板参数对象的地址(该对象只存在于类类型的模板参数中!)当然是一个常量表达式,可以用作另一个模板参数。模板参数对象被明确提到在常量表达式中可用([expr.const]/4.5)。