【发布时间】:2016-04-28 05:43:48
【问题描述】:
当我声明一个模板类时,我可以在 constexpr 成员函数中使用任何非类型模板参数,例如:
template <int Value>
struct Foo {
constexpr int value() const { return Value; }
};
我可以稍后使用这个函数来初始化 constexpr 变量,如下所示:
template <int Value>
void use_value(Foo<Value> foo) {
constexpr int baz{ foo.value() };
}
int main() {
Foo<10> bar;
use_value(bar);
}
我不明白的是,当我引用foo 时...
template <int Value>
void use_value(Foo<Value>& foo) { // by ref
constexpr int baz{ foo.value() };
}
int main() {
Foo<10> bar;
use_value(bar);
}
...clang 会告诉我foo.value() 不是常量表达式!
test.cpp:8:24: error: constexpr variable 'baz' must be initialized by a constant expression
constexpr int baz{ foo.value() };
~~^~~~~~~~~~~~~
test.cpp:13:5: note: in instantiation of function template specialization 'use_value<10>'
requested here
use_value(bar);
为什么会这样?是否与在第一个示例中编译器能够遵循 foo 的整个生命周期这一事实有关,而当通过引用获取时,程序的其他部分可能会改变实例,以某种方式影响 constexpr-ness foo.value() 的?尽管这里显然不是这种情况(鉴于模板专业化,无法更改Value 的值),但我不确定您是否确实可以通过篡改中间的实例来“破坏” constexpr 成员函数在某些情况下执行。
编辑
好的,因此引用对 constexpr 不利,因为它们具有运行时位置 - 并且 constexpr 值在生成的可执行文件中被硬编码。持续参考怎么样?这有效:
int main() {
constexpr int foo2{5};
int const& bar2{ foo2 };
}
但是对于Foo 类,更改对const 的引用将无济于事:
template <int Value>
void use_value(Foo<Value> const& foo) { // const ref
constexpr int baz = foo.value();
}
我得到相同的编译器错误。这里有什么区别?
【问题讨论】:
-
如果
Foo::value应该返回Value,你应该做它然后在use_value中使用这个静态函数(并完全丢弃参数 foo)。 -
我同意,这只是一个愚蠢的例子来说明我的意思。它并没有试图在编程方面有意义。
-
嗯,归根结底,引用只是一个语义稍有不同的指针。对于
constexpr,您需要值...
标签: c++ templates c++11 pass-by-reference constexpr