Clang 对我的代码有什么问题? GCC 和 MSVC 认为没问题
What's Clang's problem with my code? GCC and MSVC think it's fine
我正在参加 Advent of Code 挑战(2021 年第 18 天)。就像测试一样,我尝试在不同的编译器上编译它。虽然 GCC (11.2) 和 MSVC (19.30) 认为没问题,但 Clang (13.0.0) 会抛出错误列表。 link to compiler explorer
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/alloc_traits.h:514:4: error: no matching function for call to 'construct_at'
std::construct_at(__p, std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/vector.tcc:115:21: note: in instantiation of function template specialization 'std::allocator_traits<std::allocator<RegularNumber>>::construct<RegularNumber, int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>' requested here
_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
^
<source>:115:19: note: in instantiation of function template specialization 'std::vector<RegularNumber>::emplace_back<int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>' requested here
regNumVec.emplace_back(*it - '0', leftRegNumIdx,
^
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/stl_construct.h:94:5: note: candidate template ignored: substitution failure [with _Tp = RegularNumber, _Args = <int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>]: no matching constructor for initialization of 'RegularNumber'
construct_at(_Tp* __location, _Args&&... __args)
^
为什么 Clang 不理解其他两个看起来不错的东西?这是一个错误,还是我的错误?
这是“最小化”代码:
#include <algorithm>
#include <concepts>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
template <typename Type, typename Description>
class Named {
public:
using UnderlyingType = Type;
// clang-format off
constexpr Named()
noexcept(std::is_nothrow_default_constructible_v<Type>)
requires std::default_initializable<Type>
= default;
explicit constexpr Named(Type const &val)
noexcept(std::is_nothrow_copy_constructible_v<Type>)
requires std::copyable<Type>
: val_{val}
{}
explicit constexpr Named(Type&& val)
noexcept(std::is_nothrow_move_constructible_v<Type>)
requires std::movable<Type>
: val_{std::move(val)}
{}
constexpr operator Type() const&
noexcept(std::is_nothrow_copy_constructible_v<Type>)
requires std::copyable<Type>
{
return val_;
}
constexpr operator Type() const&&
noexcept(std::is_nothrow_move_constructible_v<Type>) // move assignable?
requires std::movable<Type>
{
return std::move(val_);
}
private:
Type val_;
};
// clang-format on
template <typename T>
auto readinputdata(std::istream &&is) {
auto data{std::vector<T>{}};
copy(std::istream_iterator<T>{is}, std::istream_iterator<T>{},
back_inserter(data));
return data;
}
static constexpr auto testData{
"[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]\n"
"[[[5,[2,8]],4],[5,[[9,9],0]]]\n"
"[6,[[[6,2],[5,6]],[[7,6],[4,7]]]]\n"
"[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]\n"
"[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]]\n"
"[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]]\n"
"[[[[5,4],[7,7]],8],[[8,3],8]]\n"
"[[9,3],[[9,9],[6,[4,9]]]]\n"
"[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]\n"
"[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]\n"};
struct index_for_vector_of_Pair;
using PairIndex = Named<int, index_for_vector_of_Pair>;
struct index_for_vector_of_RegularNumber;
using RegNumIndex = Named<int, index_for_vector_of_RegularNumber>;
struct RegularNumber {
using IndexType = RegNumIndex;
int value{};
RegNumIndex leftIdx{}, rightIdx{};
};
using IndexVariant = std::variant<PairIndex, RegNumIndex>;
struct Pair {
using IndexType = PairIndex;
PairIndex parent{};
IndexVariant leftIdx{}, rightIdx{};
};
static auto pairVec{std::vector<Pair>{}};
static auto regNumVec{std::vector<RegularNumber>{}};
// used for converting the input strings to pairs
static auto leftRegNumIdx{RegNumIndex{-1}};
static constexpr auto invalid_index{-1};
template <typename Type>
auto get_last_index(std::vector<Type> const &vec) {
using Index = typename Type::IndexType;
return Index{static_cast<typename Index::UnderlyingType>(size(vec))};
}
auto generate_pair(std::string::const_iterator &it, PairIndex parent)
-> PairIndex;
auto generate_side(std::string::const_iterator &it, PairIndex pairIdx)
-> IndexVariant {
if (*it == '[') {
return generate_pair(it, pairIdx);
} else {
regNumVec.emplace_back(*it - '0', leftRegNumIdx, // error on this line
RegNumIndex{invalid_index});
auto const litIdx{get_last_index(regNumVec)};
if (leftRegNumIdx != invalid_index) {
regNumVec[leftRegNumIdx].rightIdx = litIdx;
}
leftRegNumIdx = litIdx;
return litIdx;
};
}
auto generate_pair(std::string::const_iterator &it,
PairIndex parent = PairIndex{invalid_index}) -> PairIndex {
pairVec.emplace_back();
auto const pairIdx{get_last_index(pairVec)};
auto &pair{pairVec.back()};
pair.parent = parent;
++it; // skip [
pair.leftIdx = generate_side(it, pairIdx);
++it; // skip comma
pair.rightIdx = generate_side(it, pairIdx);
++it; // skip ]
return pairIdx;
}
int main() {
auto const snailFishNumbers{readinputdata<std::string>( //
std::stringstream{testData} //
)};
auto const outerPairIdxs{[&] {
auto outerPairIdxs{std::vector<PairIndex>{}};
outerPairIdxs.reserve(size(snailFishNumbers));
transform(cbegin(snailFishNumbers), cend(snailFishNumbers),
back_inserter(outerPairIdxs), [](auto const &str) {
auto it{cbegin(str)}; // need lvalue
return generate_pair(it);
});
return outerPairIdxs;
}()};
return 0;
}
您的类型是聚合
struct RegularNumber {
using IndexType = RegNumIndex;
int value{};
RegNumIndex leftIdx{}, rightIdx{};
};
其中 construct_at 尝试用圆括号初始化
::new(std::declval<void*>()) T(std::declval<Args>()...)
.
但是,聚合需要 {}
初始化器,直到编译器实现 P0960 Allow initializing aggregates from a parenthesized list of values
而且 Clang 还没有出现。 Compiler support for C++20
我正在参加 Advent of Code 挑战(2021 年第 18 天)。就像测试一样,我尝试在不同的编译器上编译它。虽然 GCC (11.2) 和 MSVC (19.30) 认为没问题,但 Clang (13.0.0) 会抛出错误列表。 link to compiler explorer
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/alloc_traits.h:514:4: error: no matching function for call to 'construct_at'
std::construct_at(__p, std::forward<_Args>(__args)...);
^~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/vector.tcc:115:21: note: in instantiation of function template specialization 'std::allocator_traits<std::allocator<RegularNumber>>::construct<RegularNumber, int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>' requested here
_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
^
<source>:115:19: note: in instantiation of function template specialization 'std::vector<RegularNumber>::emplace_back<int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>' requested here
regNumVec.emplace_back(*it - '0', leftRegNumIdx,
^
/opt/compiler-explorer/gcc-11.2.0/lib/gcc/x86_64-linux-gnu/11.2.0/../../../../include/c++/11.2.0/bits/stl_construct.h:94:5: note: candidate template ignored: substitution failure [with _Tp = RegularNumber, _Args = <int, Named<int, index_for_vector_of_RegularNumber> &, Named<int, index_for_vector_of_RegularNumber>>]: no matching constructor for initialization of 'RegularNumber'
construct_at(_Tp* __location, _Args&&... __args)
^
为什么 Clang 不理解其他两个看起来不错的东西?这是一个错误,还是我的错误?
这是“最小化”代码:
#include <algorithm>
#include <concepts>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
template <typename Type, typename Description>
class Named {
public:
using UnderlyingType = Type;
// clang-format off
constexpr Named()
noexcept(std::is_nothrow_default_constructible_v<Type>)
requires std::default_initializable<Type>
= default;
explicit constexpr Named(Type const &val)
noexcept(std::is_nothrow_copy_constructible_v<Type>)
requires std::copyable<Type>
: val_{val}
{}
explicit constexpr Named(Type&& val)
noexcept(std::is_nothrow_move_constructible_v<Type>)
requires std::movable<Type>
: val_{std::move(val)}
{}
constexpr operator Type() const&
noexcept(std::is_nothrow_copy_constructible_v<Type>)
requires std::copyable<Type>
{
return val_;
}
constexpr operator Type() const&&
noexcept(std::is_nothrow_move_constructible_v<Type>) // move assignable?
requires std::movable<Type>
{
return std::move(val_);
}
private:
Type val_;
};
// clang-format on
template <typename T>
auto readinputdata(std::istream &&is) {
auto data{std::vector<T>{}};
copy(std::istream_iterator<T>{is}, std::istream_iterator<T>{},
back_inserter(data));
return data;
}
static constexpr auto testData{
"[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]\n"
"[[[5,[2,8]],4],[5,[[9,9],0]]]\n"
"[6,[[[6,2],[5,6]],[[7,6],[4,7]]]]\n"
"[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]\n"
"[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]]\n"
"[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]]\n"
"[[[[5,4],[7,7]],8],[[8,3],8]]\n"
"[[9,3],[[9,9],[6,[4,9]]]]\n"
"[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]\n"
"[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]\n"};
struct index_for_vector_of_Pair;
using PairIndex = Named<int, index_for_vector_of_Pair>;
struct index_for_vector_of_RegularNumber;
using RegNumIndex = Named<int, index_for_vector_of_RegularNumber>;
struct RegularNumber {
using IndexType = RegNumIndex;
int value{};
RegNumIndex leftIdx{}, rightIdx{};
};
using IndexVariant = std::variant<PairIndex, RegNumIndex>;
struct Pair {
using IndexType = PairIndex;
PairIndex parent{};
IndexVariant leftIdx{}, rightIdx{};
};
static auto pairVec{std::vector<Pair>{}};
static auto regNumVec{std::vector<RegularNumber>{}};
// used for converting the input strings to pairs
static auto leftRegNumIdx{RegNumIndex{-1}};
static constexpr auto invalid_index{-1};
template <typename Type>
auto get_last_index(std::vector<Type> const &vec) {
using Index = typename Type::IndexType;
return Index{static_cast<typename Index::UnderlyingType>(size(vec))};
}
auto generate_pair(std::string::const_iterator &it, PairIndex parent)
-> PairIndex;
auto generate_side(std::string::const_iterator &it, PairIndex pairIdx)
-> IndexVariant {
if (*it == '[') {
return generate_pair(it, pairIdx);
} else {
regNumVec.emplace_back(*it - '0', leftRegNumIdx, // error on this line
RegNumIndex{invalid_index});
auto const litIdx{get_last_index(regNumVec)};
if (leftRegNumIdx != invalid_index) {
regNumVec[leftRegNumIdx].rightIdx = litIdx;
}
leftRegNumIdx = litIdx;
return litIdx;
};
}
auto generate_pair(std::string::const_iterator &it,
PairIndex parent = PairIndex{invalid_index}) -> PairIndex {
pairVec.emplace_back();
auto const pairIdx{get_last_index(pairVec)};
auto &pair{pairVec.back()};
pair.parent = parent;
++it; // skip [
pair.leftIdx = generate_side(it, pairIdx);
++it; // skip comma
pair.rightIdx = generate_side(it, pairIdx);
++it; // skip ]
return pairIdx;
}
int main() {
auto const snailFishNumbers{readinputdata<std::string>( //
std::stringstream{testData} //
)};
auto const outerPairIdxs{[&] {
auto outerPairIdxs{std::vector<PairIndex>{}};
outerPairIdxs.reserve(size(snailFishNumbers));
transform(cbegin(snailFishNumbers), cend(snailFishNumbers),
back_inserter(outerPairIdxs), [](auto const &str) {
auto it{cbegin(str)}; // need lvalue
return generate_pair(it);
});
return outerPairIdxs;
}()};
return 0;
}
您的类型是聚合
struct RegularNumber {
using IndexType = RegNumIndex;
int value{};
RegNumIndex leftIdx{}, rightIdx{};
};
其中 construct_at 尝试用圆括号初始化
::new(std::declval<void*>()) T(std::declval<Args>()...)
.
但是,聚合需要 {}
初始化器,直到编译器实现 P0960 Allow initializing aggregates from a parenthesized list of values
而且 Clang 还没有出现。 Compiler support for C++20