【问题标题】:std::variant requires default constructor in gcc 8 and 9, and not require in gcc 10/clangstd::variant 在 gcc 8 和 9 中需要默认构造函数,在 gcc 10/clang 中不需要
【发布时间】:2020-09-09 12:54:41
【问题描述】:

我无法在 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 &lt;bool X&gt;, 所有编译都很好。或者我可以删除 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")};
}

【问题讨论】:

  • @StPiere 问题的核心是 GCC 在 GCC 8 和 GCC 9 中拒绝了这个程序,但在 GCC 10 和 7 中接受了它。即,OP 想要争论“GCC 7 之后的回归”因此被纠正了,还是格式错误的 NDR?”。
  • 可能是编译器中的错误? std::variant 只需要类型是可破坏的,DefaultConstructible 什么都没有。
  • 你编译的是哪个c++版本?也许试着把最高的,例如。 -std=c++20 作为编译器标志
  • @StPiere -std=c++17, -std=c++2a 没有帮助:godbolt.org/z/3r7E6K
  • 请注意,GCC 8、9、10 的默认标准版本均为 14。

标签: c++ gcc c++17 libstdc++


【解决方案1】:

根据标准,在这种情况下没有 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.
};

所以,这显然是编译器或标准库中的实现错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 2017-07-15
    • 2019-03-01
    • 1970-01-01
    相关资源
    最近更新 更多