根据cppreference.com的说法,std::initializer_lists具有constexpr constructors和constexpr size methods(自C++14起)。
尽管我使用的编译器似乎同意constexpr初始化列表的大小确实是constexpr的,在某些情况下它却不认为我的列表是constexpr的。由于std::initializer_lists可能涉及一些“编译器魔法”,我开始怀疑constexpr是否适用于它们,与非魔法对象的方式不完全相同。
我进入了Compiler Explorer并发现主要编译器在这个问题上意见不一致。
那么以下四种情况的正确行为(根据标准)是什么呢?
我能找到的最相似的问题是给std::array赋值initializer_list,但那里面的细节是针对std::array的,而不适用于我的示例。
尽管我使用的编译器似乎同意constexpr初始化列表的大小确实是constexpr的,在某些情况下它却不认为我的列表是constexpr的。由于std::initializer_lists可能涉及一些“编译器魔法”,我开始怀疑constexpr是否适用于它们,与非魔法对象的方式不完全相同。
我进入了Compiler Explorer并发现主要编译器在这个问题上意见不一致。
那么以下四种情况的正确行为(根据标准)是什么呢?
#include <initializer_list>
using size_type = std::initializer_list<int>::size_type;
template <typename T>
size_type Foo(std::initializer_list<T> const &list) {
return list.size();
}
int main() {
// 1. Example based on
// https://en.cppreference.com/w/cpp/utility/initializer_list/size
// gcc: works
// clang: no viable c'tor or deduction guide
// msvc: works
static_assert(std::initializer_list{1, 2, 3}.size() == 3);
// 2. Make a constexpr std::initializer_list<T> with T deduced
// gcc: not constant expression
// clang: no viable c'tor or deduction guide
// msvc: works
constexpr auto the_list = std::initializer_list{1, 2, 3};
// 3. Static assert using constexpr size
// gcc: fails because of above
// clang: fails because of above
// msvc: works
static_assert(the_list.size() == 3);
// 4. Extract the size via a constexpr function
// gcc: fails because of above
// clang: fails because of above
// msvc: expression did not evaluate to a constant
constexpr auto the_list_size = Foo(the_list);
return 0;
}
- "gcc" 指的是带有
-std=c++20
(也经过 13.1 版本测试)的 x86-64 gcc(主干版本) - "clang" 指的是带有
-std=c++20
(也经过 16.0.0 版本测试)的 x86-64 clang(主干版本) - "msvc" 指的是带有
/std:c++20
的 x64 msvc v19.latest
我本来期望这四种情况都能编译通过。但是一些编译器拒绝了其中一些情况,让我重新考虑我的理解。编译器是否拒绝了正确的代码(或接受了错误的代码)?我是否无意中依赖于实现定义的行为?标准是否存在歧义?
我能找到的最相似的问题是给std::array赋值initializer_list,但那里面的细节是针对std::array的,而不适用于我的示例。
Foo
没有标记为constexpr
... - Jarod42Foo
没有标记为constexpr
... - Jarod42initializer_list
没有可行的推导指南的错误是一个bug,该bug在issues/60876中进行了跟踪。 - 康桓瑋initializer_list
没有可行的推导指南的错误是一个bug,已在issues/60876进行追踪。 - 康桓瑋initializer_list
没有可行的推导指南的错误是一个bug,该bug已在issues/60876中进行跟踪。 - undefined