size()
和std::initializer_list
的{{1}}成员函数具有相同的签名:
std::array
两者均为constexpr size_type size() const noexcept;
。但是,constexpr
可以在std::array::size()
上下文中使用,但是constexpr
不能:
std::initializer_list::size()
(*)错误是:
std::initializer_list<int> il{1, 2, 3, 4}; constexpr std::size_t il_size = il.size(); // (1) - fails with GCC and Clang (*) std::array<int, 4> arr{1, 2, 3, 4}; constexpr std::size_t arr_size = arr.size(); // (2) - OK
As far as I understand,因为(1)失败而(2)成功,这一事实是完全合理的,因为类模板的in 'constexpr' expansion of 'il.std::initializer_list<int>::size()'
error: the value of 'il' is not usable in a constant expression
成员函数可能无法满足constexpr
的要求。
我有两个相关的问题:
constexpr
不能以std::initializer_list
的编译方式实现?标准中是否有阻止这种实现的措施? 鉴于(1)
失败,将(1)
标记为std::initializer_list::size()
的目的是什么?唯一的用例似乎就是这个:
constexpr
答案 0 :(得分:4)
为什么
std::initializer_list
的实现方式不像(1)那样编译?标准中是否有某些东西阻止这种实现?
是的,这是不可能的。 initializer_list
可以具有任何大小,您不能在恒定的评估时间内获得任意运行时initializer_list
的大小。这与std::array
完全不同,在std::array<T, N>
中,给定的N
的大小为struct X { int i; };
X x{42};
constexpr X cx{17};
constexpr int i = x.i; // error
constexpr int ci = cx.i; // ok
。一个人的大小是可变的,另一个人的大小是固定的。
这与其他任何变量都没有真正的区别:
std::initializer_list::size()
鉴于(1)失败,将
constexpr
标记为constexpr
的目的是什么?唯一的用例似乎就是这个
这不是唯一的用例,远非如此。 constexpr
个成员函数不仅允许您在initializer_list
个对象上调用它们。通常,它们使您可以在持续评估时间内在任何地方调用它们。
也就是说,在进行任何形式的持续评估时,如果创建constexpr size_t four() {
std::initializer_list<int> lst = {1, 2, 3, 4};
return lst.size();
}
static_assert(four() == 4);
,则可以使用其大小。一个愚蠢的最小示例可能是:
lst
请注意,constexpr
本身不是four()
对象,它只是在不断求值期间评估对size()
的调用的过程中创建的一些短暂的东西。但是我们仍然需要constexpr
成为constexpr
-调用任何非std::initializer_list
函数都是不行的。
从这里您可以将其向外扩展到您可能想要运行的任意代码,在持续评估期间的某个时刻,它想要确定\((?!http)
的大小。
答案 1 :(得分:2)
不是std::initializer_list::size
不能在常量表达式中使用。例如,以下可能(请参见脚注)should compile:
#include <initializer_list>
int main() {
constexpr int x = (std::initializer_list<int>{1, 2, 3, 4}).size();
static_assert(x == 4);
}
但是,您的调用方式大概是size
方法必须对std::initializer_list
对象的一个成员执行从左到右的转换,这违反了约束。关于常量表达式(C ++ 17 [expr.const] /(2.7))。
在我的示例中,相应的从左值到右值的转换发生在“文字类型的非易失性glvalue上,该值引用寿命在其内开始的非易失性对象
e
;的求值”,这使其可以使用(C ++ 17 [expr.const] /(2.7.4))。
在std::array
示例中,由于返回了模板参数,因此可能没有左值到右值的转换。
脚注:请参见LWG 2833。