std::variant 在 gcc 8 和 9 中需要默认构造函数,在 gcc 10/clang 中不需要
std::variant requires default constructor in gcc 8 and 9, and not require in gcc 10/clang
我无法在 Ubuntu 20.04.1 / gcc 9.3.0 上编译以下代码。
根据 https://godbolt.org/ 它可以用 gcc 10.x 编译得很好,
和 gcc 7.x,但给出:
In file included from /usr/include/c++/9/variant:36,
from test.cpp:1:
/usr/include/c++/9/type_traits: In instantiation of ‘struct std::__is_nt_default_constructible_atom<Foo>’:
/usr/include/c++/9/type_traits:945:12: required from ‘struct std::__is_nt_default_constructible_impl<Foo, false>’
/usr/include/c++/9/type_traits:131:12: required from ‘struct std::__and_<std::is_default_constructible<Foo>, std::__is_nt_default_constructible_impl<Foo, false> >’
/usr/include/c++/9/type_traits:951:12: required from ‘struct std::is_nothrow_default_constructible<Foo>’
/usr/include/c++/9/type_traits:2965:25: required from ‘constexpr const bool std::is_nothrow_default_constructible_v<Foo>’
/usr/include/c++/9/variant:301:4: [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/c++/9/type_traits:883:12: recursively required from ‘constexpr std::variant<_Types>::variant() [with _Types = {Foo, Boo}]’
/usr/include/c++/9/type_traits:883:12: required from ‘struct std::is_constructible<std::variant<Foo, Boo> >’
/usr/include/c++/9/type_traits:889:12: required from ‘struct std::is_default_constructible<std::variant<Foo, Boo> >’
/usr/include/c++/9/type_traits:2921:25: required from ‘constexpr const bool std::is_default_constructible_v<std::variant<Foo, Boo> >’
/usr/include/c++/9/variant:273:4: required from ‘constexpr const bool std::__detail::__variant::_Traits<std::variant<Foo, Boo>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<c\
har> > >::_S_default_ctor’
/usr/include/c++/9/variant:1219:11: required from ‘class std::variant<std::variant<Foo, Boo>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >’
test.cpp:32:53: required from here
/usr/include/c++/9/type_traits:931:47: error: ‘Foo::Foo()’ is private within this context
931 | : public integral_constant<bool, noexcept(_Tp())>
| ^~~~~
test.cpp:10:3: note: declared private here
10 | Foo() noexcept {}
| ^~~
使用 gcc 8.x 和 9.x。下面的代码有问题吗?
请注意,如果在下面的代码中删除 template <bool X>
,
所有编译都很好。或者我可以删除 main 中的代码,并且所有编译都很好。
#include <variant>
#include <string>
struct Foo {
public:
explicit Foo(int) noexcept {}
Foo(Foo &&) noexcept = default;
Foo &operator=(Foo &&) = default;
private:
Foo() noexcept {}
};
struct Boo {
public:
explicit Boo(int) noexcept {}
Boo(Boo &&) noexcept = default;
Boo &operator=(Boo &&) = default;
private:
Boo() noexcept {}
};
template<bool X>
std::variant<Foo, Boo> g(int v, int x) {
return v == 0 ? std::variant<Foo, Boo>{Foo{x}} :
std::variant<Foo, Boo>{Boo{x}};
}
int main()
{
std::variant<std::variant<Foo, Boo>, std::string> err{std::string("aaa")};
}
根据标准,在这种情况下没有 DefaultConstructible 要求。
本身的变体可以是 Non-DefaultConstructible(在本例中,内部和外部变体都是这种情况)。
如果移除或删除 Foo() 私有构造函数,code works(如预期):
struct Foo {
public:
explicit Foo(int) noexcept {}
Foo(Foo &&) noexcept = default;
Foo &operator=(Foo &&) = default;
private:
// Foo() noexcept {} -> comment out works
Foo() = deleted; // -> works also.
};
所以,这显然是编译器或标准库中的实现错误。
我无法在 Ubuntu 20.04.1 / gcc 9.3.0 上编译以下代码。 根据 https://godbolt.org/ 它可以用 gcc 10.x 编译得很好, 和 gcc 7.x,但给出:
In file included from /usr/include/c++/9/variant:36,
from test.cpp:1:
/usr/include/c++/9/type_traits: In instantiation of ‘struct std::__is_nt_default_constructible_atom<Foo>’:
/usr/include/c++/9/type_traits:945:12: required from ‘struct std::__is_nt_default_constructible_impl<Foo, false>’
/usr/include/c++/9/type_traits:131:12: required from ‘struct std::__and_<std::is_default_constructible<Foo>, std::__is_nt_default_constructible_impl<Foo, false> >’
/usr/include/c++/9/type_traits:951:12: required from ‘struct std::is_nothrow_default_constructible<Foo>’
/usr/include/c++/9/type_traits:2965:25: required from ‘constexpr const bool std::is_nothrow_default_constructible_v<Foo>’
/usr/include/c++/9/variant:301:4: [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/c++/9/type_traits:883:12: recursively required from ‘constexpr std::variant<_Types>::variant() [with _Types = {Foo, Boo}]’
/usr/include/c++/9/type_traits:883:12: required from ‘struct std::is_constructible<std::variant<Foo, Boo> >’
/usr/include/c++/9/type_traits:889:12: required from ‘struct std::is_default_constructible<std::variant<Foo, Boo> >’
/usr/include/c++/9/type_traits:2921:25: required from ‘constexpr const bool std::is_default_constructible_v<std::variant<Foo, Boo> >’
/usr/include/c++/9/variant:273:4: required from ‘constexpr const bool std::__detail::__variant::_Traits<std::variant<Foo, Boo>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<c\
har> > >::_S_default_ctor’
/usr/include/c++/9/variant:1219:11: required from ‘class std::variant<std::variant<Foo, Boo>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >’
test.cpp:32:53: required from here
/usr/include/c++/9/type_traits:931:47: error: ‘Foo::Foo()’ is private within this context
931 | : public integral_constant<bool, noexcept(_Tp())>
| ^~~~~
test.cpp:10:3: note: declared private here
10 | Foo() noexcept {}
| ^~~
使用 gcc 8.x 和 9.x。下面的代码有问题吗?
请注意,如果在下面的代码中删除 template <bool X>
,
所有编译都很好。或者我可以删除 main 中的代码,并且所有编译都很好。
#include <variant>
#include <string>
struct Foo {
public:
explicit Foo(int) noexcept {}
Foo(Foo &&) noexcept = default;
Foo &operator=(Foo &&) = default;
private:
Foo() noexcept {}
};
struct Boo {
public:
explicit Boo(int) noexcept {}
Boo(Boo &&) noexcept = default;
Boo &operator=(Boo &&) = default;
private:
Boo() noexcept {}
};
template<bool X>
std::variant<Foo, Boo> g(int v, int x) {
return v == 0 ? std::variant<Foo, Boo>{Foo{x}} :
std::variant<Foo, Boo>{Boo{x}};
}
int main()
{
std::variant<std::variant<Foo, Boo>, std::string> err{std::string("aaa")};
}
根据标准,在这种情况下没有 DefaultConstructible 要求。
本身的变体可以是 Non-DefaultConstructible(在本例中,内部和外部变体都是这种情况)。
如果移除或删除 Foo() 私有构造函数,code works(如预期):
struct Foo {
public:
explicit Foo(int) noexcept {}
Foo(Foo &&) noexcept = default;
Foo &operator=(Foo &&) = default;
private:
// Foo() noexcept {} -> comment out works
Foo() = deleted; // -> works also.
};
所以,这显然是编译器或标准库中的实现错误。