Clang、std::next、libstdc++ 和 constexpr-ness
Clang, std::next, libstdc++ and constexpr-ness
取以下代码:
#include <array>
constexpr std::array<int, 10> a{};
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
使用 -std=c++17
GCC 可以完美地编译它,但 Clang 抱怨该表达式不是整型常量表达式。看起来问题出在 std::next
上,但是在 C++17 中应该是 constexpr
。
然而,std::next
在标准库中,而不是在编译器本身中,因此发生了一些奇怪的事情。为了让事情变得更好,如果您将 -stdlib=libc++
传递给 Clang,该示例将完美编译。
这是怎么回事?谁对谁错?
编辑
这个问题似乎与 clang toolchain-ed 在 godbolt 中针对 GCC 7.2 有关。如果将 --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot
参数添加到命令行,一切都会完美无缺。 (感谢@einpoklum 向 godbolt 报告了这个问题——我的速度变慢了;))
编辑
对于那些认为旧编译器应该适用于实际标准的人来说,很抱歉,这种考虑毫无意义。我说的是 GCC 和 Clang 的最新版本。并且问题在两者的主干版本中都可以重现。较旧的编译器与此问题无关(相反,MSVC 行为会很有趣)。
在 Wandbox 中编译
#include <array>
int main()
{
constexpr std::array<int, 10> a{};
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
}
使用 clang++ 4.0.1 和命令行
clang++ prog.cc -Wall -Wextra -std=c++1z
我收到错误
prog.cc:6:18: error: static_assert expression is not an integral constant expression
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:6:18: note: non-constexpr function 'next<const int *>' cannot be used in a constant expression
/opt/wandbox/clang-4.0.1/include/c++/v1/iterator:599:1: note: declared here
next(_InputIter __x,
^
1 error generated.
但使用 clang++ 5.0.0(或 6.0.0 或 7.0.0 HEAD)编译
clang++ prog.cc -Wall -Wextra -std=c++17
所以clang++ 4.0.1对C++17的支持似乎很低(and/or clang++使用的库),在以下版本中更正。
-- 编辑--
问题已在 gobold.
中针对 clang++ 5.0.0 和 clang++ 6.0.0 得到确认(参见 einpoklum 的回答)
所以我想问题是 libstdc++ 的版本:似乎 gobold 正在使用一个版本(我想是旧版本),而 std::next()
不是定义为 constexpr
,其中 wandbox 使用的版本 std::next()
是 constexpr
。
使用 GodBolt.org 上的 Clang 6.0.0 和 5.0.0 版本,您的代码确实 fail to compile。但是 - 在我的系统(Lubuntu 17.10)上使用 clang 5.0.0-3,它似乎编译没有错误。
这是一种奇怪的行为。因此,也许不是您问题的最佳答案,但面对这样的事情,我会在 bugs.llvm.org 上报告它,看看 clang/LLVM 开发人员怎么说。
取以下代码:
#include <array>
constexpr std::array<int, 10> a{};
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
使用 -std=c++17
GCC 可以完美地编译它,但 Clang 抱怨该表达式不是整型常量表达式。看起来问题出在 std::next
上,但是在 C++17 中应该是 constexpr
。
然而,std::next
在标准库中,而不是在编译器本身中,因此发生了一些奇怪的事情。为了让事情变得更好,如果您将 -stdlib=libc++
传递给 Clang,该示例将完美编译。
这是怎么回事?谁对谁错?
编辑
这个问题似乎与 clang toolchain-ed 在 godbolt 中针对 GCC 7.2 有关。如果将 --gcc-toolchain=/opt/compiler-explorer/gcc-snapshot
参数添加到命令行,一切都会完美无缺。 (感谢@einpoklum 向 godbolt 报告了这个问题——我的速度变慢了;))
编辑
对于那些认为旧编译器应该适用于实际标准的人来说,很抱歉,这种考虑毫无意义。我说的是 GCC 和 Clang 的最新版本。并且问题在两者的主干版本中都可以重现。较旧的编译器与此问题无关(相反,MSVC 行为会很有趣)。
在 Wandbox 中编译
#include <array>
int main()
{
constexpr std::array<int, 10> a{};
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
}
使用 clang++ 4.0.1 和命令行
clang++ prog.cc -Wall -Wextra -std=c++1z
我收到错误
prog.cc:6:18: error: static_assert expression is not an integral constant expression
static_assert(std::next(std::begin(a)) == std::begin(a) + 1);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:6:18: note: non-constexpr function 'next<const int *>' cannot be used in a constant expression
/opt/wandbox/clang-4.0.1/include/c++/v1/iterator:599:1: note: declared here
next(_InputIter __x,
^
1 error generated.
但使用 clang++ 5.0.0(或 6.0.0 或 7.0.0 HEAD)编译
clang++ prog.cc -Wall -Wextra -std=c++17
所以clang++ 4.0.1对C++17的支持似乎很低(and/or clang++使用的库),在以下版本中更正。
-- 编辑--
问题已在 gobold.
中针对 clang++ 5.0.0 和 clang++ 6.0.0 得到确认(参见 einpoklum 的回答)所以我想问题是 libstdc++ 的版本:似乎 gobold 正在使用一个版本(我想是旧版本),而 std::next()
不是定义为 constexpr
,其中 wandbox 使用的版本 std::next()
是 constexpr
。
使用 GodBolt.org 上的 Clang 6.0.0 和 5.0.0 版本,您的代码确实 fail to compile。但是 - 在我的系统(Lubuntu 17.10)上使用 clang 5.0.0-3,它似乎编译没有错误。
这是一种奇怪的行为。因此,也许不是您问题的最佳答案,但面对这样的事情,我会在 bugs.llvm.org 上报告它,看看 clang/LLVM 开发人员怎么说。