【问题标题】:Why an object is not constructible?为什么一个对象是不可构造的?
【发布时间】:2021-02-20 22:13:05
【问题描述】:

我有以下代码

class MyValue
{
    std::any value;
    MyValue(std::any value)
        : value(value)
    {
    }

public:
    using ErrorType = std::string;
    using MaybeMy = std::variant<ErrorType, MyValue>;

    static MaybeMy safeWrap(std::any const &obj) noexcept
    {
        if (std::any_cast<int>(&obj) != nullptr)
            return MyValue(obj);
        else
            return ErrorType("There is some alien type");
    }
    operator std::string() const
    {
        return std::to_string(std::any_cast<int>(value));
    }
    MyValue(MyValue &&) = default;
};

int main()
{
    auto printer = [](auto &&v) { std::cout << std::string(v) << std::endl; };
    MyValue::MaybeMy as[] = {MyValue::safeWrap(10), MyValue::safeWrap("10")};
    for (auto &&v : as)
        std::visit(printer, v);
}

但我收到与 std::variant 相关的错误 - MyValue 不可构造。 我无法理解其中的原因。

为什么MyValue 不可构造?为什么执行代码会有一些限制?

编译器的输出:

[build] In file included from /usr/include/c++/9/variant:36,
[build]  from /home/created/Documents/Cpp/gstream_test/main.cpp:8:
[build] /usr/include/c++/9/type_traits: In instantiation of ‘struct std::__and_<std::is_copy_constructible<MyValue>, std::is_constructible<MyValue, const MyValue&> >’:
[build] /usr/include/c++/9/any:181:58:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous>, typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const MyValue&; _Tp = MyValue; _Mgr = std::any::_Manager_external<MyValue>; typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous> = <missing>; typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> = <missing>]’
[build] /usr/include/c++/9/type_traits:883:12:   required from ‘struct std::is_constructible<MyValue, const MyValue&>’
[build] /usr/include/c++/9/type_traits:901:12:   required from ‘struct std::__is_copy_constructible_impl<MyValue, true>’
[build] /usr/include/c++/9/type_traits:907:12:   required from ‘struct std::is_copy_constructible<MyValue>’
[build] /usr/include/c++/9/type_traits:2925:25:   required from ‘constexpr const bool std::is_copy_constructible_v<MyValue>’
[build] /usr/include/c++/9/variant:275:5:   required from ‘constexpr const bool std::__detail::__variant::_Traits<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, MyValue>::_S_copy_ctor’
[build] /usr/include/c++/9/variant:1220:11:   required from ‘class std::variant<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, MyValue>’
[build] /home/created/Documents/Cpp/gstream_test/main.cpp:26:5:   required from here
[build] /usr/include/c++/9/type_traits:131:12: error: incomplete type ‘std::is_copy_constructible<MyValue>’ used in nested name specifier
[build]   131 |     struct __and_<_B1, _B2>
[build]       |            ^~~~~~~~~~~~~~~~
[build] /usr/include/c++/9/type_traits: In instantiation of ‘struct std::__and_<std::is_copy_constructible<MyValue>, std::__not_<std::is_constructible<MyValue, const MyValue&> >, std::__not_<std::__is_in_place_type<MyValue> > >’:
[build] /usr/include/c++/9/type_traits:150:27:   required from ‘constexpr const bool std::__and_v<std::is_copy_constructible<MyValue>, std::__not_<std::is_constructible<MyValue, const MyValue&> >, std::__not_<std::__is_in_place_type<MyValue> > >’
[build] /usr/include/c++/9/any:192:27:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const MyValue&; _Tp = MyValue; _Mgr = std::any::_Manager_external<MyValue>; typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> = <missing>]’
[build] /usr/include/c++/9/type_traits:883:12:   required from ‘struct std::is_constructible<MyValue, const MyValue&>’
[build] /usr/include/c++/9/type_traits:901:12:   required from ‘struct std::__is_copy_constructible_impl<MyValue, true>’
[build] /usr/include/c++/9/type_traits:907:12:   required from ‘struct std::is_copy_constructible<MyValue>’
[build] /usr/include/c++/9/type_traits:2925:25:   required from ‘constexpr const bool std::is_copy_constructible_v<MyValue>’
[build] /usr/include/c++/9/variant:275:5:   required from ‘constexpr const bool std::__detail::__variant::_Traits<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, MyValue>::_S_copy_ctor’
[build] /usr/include/c++/9/variant:1220:11:   required from ‘class std::variant<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, MyValue>’
[build] /home/created/Documents/Cpp/gstream_test/main.cpp:26:5:   required from here
[build] /usr/include/c++/9/type_traits:136:12: error: incomplete type ‘std::is_copy_constructible<MyValue>’ used in nested name specifier
[build]   136 |     struct __and_<_B1, _B2, _B3, _Bn...>
[build]       |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[build] /usr/include/c++/9/type_traits: In instantiation of ‘constexpr const bool std::__and_v<std::is_copy_constructible<MyValue>, std::__not_<std::is_constructible<MyValue, const MyValue&> >, std::__not_<std::__is_in_place_type<MyValue> > >’:
[build] /usr/include/c++/9/any:192:27:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const MyValue&; _Tp = MyValue; _Mgr = std::any::_Manager_external<MyValue>; typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> = <missing>]’
[build] /usr/include/c++/9/type_traits:883:12:   required from ‘struct std::is_constructible<MyValue, const MyValue&>’
[build] /usr/include/c++/9/type_traits:901:12:   required from ‘struct std::__is_copy_constructible_impl<MyValue, true>’
[build] /usr/include/c++/9/type_traits:907:12:   required from ‘struct std::is_copy_constructible<MyValue>’
[build] /usr/include/c++/9/type_traits:2925:25:   required from ‘constexpr const bool std::is_copy_constructible_v<MyValue>’
[build] /usr/include/c++/9/variant:275:5:   required from ‘constexpr const bool std::__detail::__variant::_Traits<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, MyValue>::_S_copy_ctor’
[build] /usr/include/c++/9/variant:1220:11:   required from ‘class std::variant<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, MyValue>’
[build] /home/created/Documents/Cpp/gstream_test/main.cpp:26:5:   required from here
[build] /usr/include/c++/9/type_traits:150:27: error: ‘value’ is not a member of ‘std::__and_<std::is_copy_constructible<MyValue>, std::__not_<std::is_constructible<MyValue, const MyValue&> >, std::__not_<std::__is_in_place_type<MyValue> > >’
[build]   150 |     inline constexpr bool __and_v = __and_<_Bn...>::value;
[build]       |                           ^~~~~~~

我使用的是 gcc 9.3

【问题讨论】:

  • 请不要只是挥手错误,而是发布实际的错误消息。
  • 无法复制。 Compiles for me
  • @IgorTandetnik 他使用gcc 9.3
  • @MarekR 好吧,也可以用gcc 10 编译。很可能是在更高版本中修复的编译器错误。

标签: c++


【解决方案1】:

这是一个 gcc 错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90415

它已在 gcc 8 和 gcc 10+ 中修复。

当您有一个构造函数采用 std::any 时会发生错误,该构造函数很早就实例化了一些类型特征并破坏了一些东西,并在您尝试移动类型时犯了一个硬错误(因为它还考虑到隐式转换为 @ 987654325@)

一种解决方法是不让构造函数采用std::any,方法是添加一个虚拟参数:

    MyValue(int, std::any value)
        : value(value)
    {
    }

    // ...

        return MyValue(0, obj);

或者改用std::experimental::any/std::experimental::fundamentals_v1::any

【讨论】:

  • 我认为返回类型 std::variant 会发生这种情况。因为如果我改成MyValue*it也编译好了。
  • @SergeyB std::variant 尝试从您创建的临时移动。尝试使用移动构造函数会导致问题发生:godbolt.org/z/6nxfYs
【解决方案2】:

类成员的默认可访问性是私有的。由于您的构造函数位于 public: 声明之前,因此没有人可以构造此类的任何对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-29
    • 2022-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    相关资源
    最近更新 更多