在最近询问another question时,我偶然发现了GCC在使用参数包扩展后跟另一个元素初始化std::array
时的一些奇怪行为。我已经与Jarod42 in the comments there进行了简短的讨论,但我认为最好将其作为一个新问题。
例如,请考虑以下代码,该代码应该提供实用程序make_array
函数,该函数接受任意数量的参数并将std::forward
它们用于std::array
初始化。前导标记参数选择是否应使用默认构造的T
(通过std::true_type
选择)终止数组(通过std::false_type
选择)。然后我用静态创建一个整数数组,用自动存储持续时间创建一次。最后打印出数组元素。
#include <array> // std::array
#include <cstddef> // std::size_t
#include <iomanip> // std::setw
#include <ios> // std::left, std::right
#include <iostream> // std::cout
#include <string> // std::string
#include <type_traits> // std::false_type, std::true_type
// This is only used for visualization.
template <typename T, std::size_t N>
void
print_array(const std::string& name, const std::array<T, N>& arr)
{
std::cout << std::setw(20) << std::left << (name + ":") << std::right << "{";
for (auto iter = arr.cbegin(); iter != arr.cend(); ++iter)
std::cout << (iter != arr.cbegin() ? ", " : "") << std::setw(2) << *iter;
std::cout << "}\n";
}
// Create a `std::array<T>` with elements constructed from the provided
// arguments.
template <typename T, typename... ArgTs>
static constexpr auto
make_array(std::false_type, ArgTs&&... args) noexcept
{
std::array<T, sizeof...(args)> values = { { std::forward<ArgTs>(args)... } };
return values;
}
// Create a `std::array<T>` with elements constructed from the provided
// arguments followed by a default-constructed `T`.
template <typename T, typename... ArgTs>
static constexpr auto
make_array(std::true_type, ArgTs&&... args) noexcept
{
std::array<T, sizeof...(args) + 1> values = {
{ std::forward<ArgTs>(args)..., T {} }
};
return values;
}
namespace /* anonymous */
{
const auto values_no_static = make_array<int>(std::false_type(), 1, 2, 3, 4);
const auto values_yes_static = make_array<int>(std::true_type(), 1, 2, 3, 4);
}
int
main()
{
const auto values_no_automatic = make_array<int>(std::false_type(), 1, 2, 3, 4);
const auto values_yes_automatic = make_array<int>(std::true_type(), 1, 2, 3, 4);
print_array("static yes", values_yes_static);
print_array("static no", values_no_static);
print_array("automatic yes", values_yes_automatic);
print_array("automatic no", values_no_automatic);
}
我希望看到阵列{1, 2, 3, 4}
和{1, 2, 3, 4, 0}
打印两次。这就是Clang所做的。但是,GCC会为具有静态存储持续时间的已终止阵列打印{0, 0, 0, 0, 0}
。如果我使用T {}
替换初始值设定项列表中的尾随-1
,我会改为{0, 0, 0, 0, -1}
。因此,添加尾随元素似乎会导致参数包扩展为全零。但仅当结果std::array
具有静态存储持续时间时。
我是否调用了未定义的行为,或者这是GCC中的错误?如果它是不确定的行为,我会感谢官方参考标准。我已经知道一个解决这个问题的简单方法(参见my answer上面提到的问题)而不是有兴趣避免这个问题。相反,我想知道代码是否格式正确,如果是,那么哪个编译器是正确的。
使用GCC完成输出:
$ g++ --version
g++ (GCC) 5.1.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
$ g++ -std=c++14 -o main_gcc -Wall -Wextra -Werror -pedantic main.cxx
$
$ ./main_gcc
static yes: { 0, 0, 0, 0, 0}
static no: { 1, 2, 3, 4}
automatic yes: { 1, 2, 3, 4, 0}
automatic no: { 1, 2, 3, 4}
使用Clang:
$ clang --version
clang version 3.6.2 (tags/RELEASE_362/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
$
$ clang -std=c++14 -o main_clang -Wall -Wextra -Werror -pedantic main.cxx -lstdc++
$
$ ./main_clang
static yes: { 1, 2, 3, 4, 0}
static no: { 1, 2, 3, 4}
automatic yes: { 1, 2, 3, 4, 0}
automatic no: { 1, 2, 3, 4}
答案 0 :(得分:3)
最小复制样本:
i
willTransitionFrom()。到目前为止,我们可以肯定地说没有诱导UB。
请注意我们如何解决这个问题:
将validate()
语句更改为Change the 0
to a 1
取代jQuery("input[type='text'], textarea").on("input", function () {
var isValid = validate();
if (isValid) {
jQuery("#subnewtide").removeAttr("disabled");
} else {
jQuery("#subnewtide").attr("disabled", "disabled");
}
});
function validate() {
var isValid = true;
$('input, textarea').each(function() {
if ($(this).val() === '')
isValid = false;
});
return isValid;
}
取代id="new_tide"
return a correspondingly constructed temporary
答案 1 :(得分:1)
我已经向GCC开发者报告过了。它被认为是bug 67104并于2015年8月针对海湾合作委员会6进行了修复,并后移到了GCC 5.3。您可以使用Columbo's answer中提供的在线编译器链接进行检查。