【问题标题】:Cannot pass std::vector<bool> to winrt::array_view无法将 std::vector<bool> 传递给 winrt::array_view
【发布时间】:2019-07-22 19:56:24
【问题描述】:

我试图通过 C++/WinRT 库使用 Windows::Gaming::Input::RawGameController

调用RawGameController::GetCurrentReading()获取当前控制器状态:

std::vector<bool> buttonsArray(rawController.ButtonCount(), false);
std::vector<GameControllerSwitchPosition> switchesArray(rawController.SwitchCount(), GameControllerSwitchPosition::Center);
std::vector<double> axisArray(rawController.AxisCount(), 0.0);
uint64_t timestamp = rawController.GetCurrentReading(buttonsArray, switchesArray, axisArray);

并且有编译错误:

1>------ Build started: Project: cppwinrtgamepad, Configuration: Debug x64 ------
1>cppwinrtgamepad.cpp
1>c:\somepath\x64\debug\generated files\winrt\base.h(3458): error C2039: 'data': is not a member of 'std::vector<T,std::allocator<_Ty>>'
1>        with
1>        [
1>            T=bool,
1>            _Ty=bool
1>        ]
1>c:\somepath\x64\debug\generated files\winrt\base.h(3663): note: see declaration of 'std::vector<T,std::allocator<_Ty>>'
1>        with
1>        [
1>            T=bool,
1>            _Ty=bool
1>        ]
1>c:\somepath\cppwinrtgamepad.cpp(121): note: see reference to function template instantiation 'winrt::array_view<T>::array_view<T>(std::vector<T,std::allocator<_Ty>> &) noexcept' being compiled
1>        with
1>        [
1>            T=bool,
1>            _Ty=bool
1>        ]
1>c:\somepath\cppwinrtgamepad.cpp(121): note: see reference to function template instantiation 'winrt::array_view<T>::array_view<T>(std::vector<T,std::allocator<_Ty>> &) noexcept' being compiled
1>        with
1>        [
1>            T=bool,
1>            _Ty=bool
1>        ]
1>c:\somepath\cppwinrtgamepad.cpp(90): note: see reference to class template instantiation 'winrt::impl::fast_iterator<winrt::Windows::Foundation::Collections::IVectorView<winrt::Windows::Gaming::Input::Gamepad>>' being compiled
1>c:\somepath\x64\debug\generated files\winrt\base.h(7801): note: see reference to class template instantiation 'winrt::com_ptr<winrt::impl::IContextCallback>' being compiled
1>c:\somepath\x64\debug\generated files\winrt\base.h(7573): note: see reference to class template instantiation 'winrt::com_ptr<winrt::impl::IServerSecurity>' being compiled
1>c:\somepath\x64\debug\generated files\winrt\base.h(7532): note: see reference to class template instantiation 'std::chrono::time_point<winrt::clock,winrt::Windows::Foundation::TimeSpan>' being compiled
1>c:\somepath\x64\debug\generated files\winrt\base.h(5264): note: see reference to class template instantiation 'winrt::com_ptr<winrt::impl::IMarshal>' being compiled
1>c:\somepath\x64\debug\generated files\winrt\base.h(2503): note: see reference to class template instantiation 'winrt::com_ptr<To>' being compiled
1>        with
1>        [
1>            To=winrt::impl::ILanguageExceptionErrorInfo2
1>        ]
1>c:\somepath\x64\debug\generated files\winrt\base.h(4120): note: see reference to function template instantiation 'winrt::com_ptr<To> winrt::com_ptr<winrt::impl::IRestrictedErrorInfo>::try_as<winrt::impl::ILanguageExceptionErrorInfo2>(void) noexcept const' being compiled
1>        with
1>        [
1>            To=winrt::impl::ILanguageExceptionErrorInfo2
1>        ]
1>c:\somepath\x64\debug\generated files\winrt\base.h(4202): note: see reference to class template instantiation 'winrt::com_ptr<winrt::impl::IRestrictedErrorInfo>' being compiled
1>c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.16.27023\include\string_view(39): note: see reference to class template instantiation 'std::basic_string_view<wchar_t,std::char_traits<wchar_t>>' being compiled
1>c:\somepath\x64\debug\generated files\winrt\base.h(3458): error C2664: 'winrt::array_view<T>::array_view(winrt::array_view<T> &&)': cannot convert argument 1 from 'winrt::array_view<T>::size_type' to 'std::initializer_list<bool>'
1>        with
1>        [
1>            T=bool
1>        ]
1>c:\somepath\x64\debug\generated files\winrt\base.h(3459): note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>Done building project "cppwinrtgamepad.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

GetCurrentReading()winrt/Windows.Gaming.Input.h 中定义如下:

template <typename D> uint64_t consume_Windows_Gaming_Input_IRawGameController<D>::GetCurrentReading(array_view<bool> buttonArray, array_view<Windows::Gaming::Input::GameControllerSwitchPosition> switchArray, array_view<double> axisArray) const

而对应的winrt::array_view构造函数在winrt/base.h中定义如下:

template <typename C>
array_view(std::vector<C>& value) noexcept :
    array_view(value.data(), static_cast<size_type>(value.size()))
{}

考虑到std::vector&lt;bool&gt; 根本不限制data() 方法,这看起来像是一个不经意的错误。 或者有其他推荐的方式拨打RawGameController::GetCurrentReading()

PS:作为一种解决方法,我可以使用std::array&lt;bool, SOME_BIG_BUTTTON_COUNT&gt;,但它太丑了。

【问题讨论】:

  • data() 上的 std::vector&lt;bool&gt; 返回什么?
  • std::vector&lt;bool&gt; 是最好避免的蠕虫罐,因为它是空间优化的(每个值一位),因此与其他 std::vector 实例化的行为在任何地方都不同。如果可以,请改用std::vector&lt;char&gt;
  • @MichaelChourdakis 问题出现在 C++/WinRT 库中,该库为 std::vectorstd::array 提供了 winrt::array_view 包装器。具体来说,它在第一个参数中有RawGameController::GetCurrentReading()array_view&lt;bool&gt;
  • @Angew 我不能使用std::vector&lt;char&gt;,因为winrt::array_view&lt;bool&gt; 不包含这样的构造函数。
  • @fdan 按钮计数不固定,我应该调用RawGameController.ButtonCount() 正确了解数组大小...我已经在 PS 中提到过。

标签: c++ uwp c++17 c++-winrt


【解决方案1】:

这是设计使然。 winrt::array_view 是一个适配器,它告诉底层 API 绑定的数组或存储具有适当的二进制布局,可以有效地接收数据(通常通过 memcpy),而无需进行某种转换。 std::vector&lt;bool&gt; 不提供该保证,因此无法使用。您可能想尝试其他方法,例如 std::array 或其他一些连续容器。

【讨论】:

  • 值得指出的是,std::vector&lt;bool&gt; 根本不是真正的容器。
  • std::array&lt;bool, SIZE&gt; 应该使用哪个数组大小?
  • 这取决于您希望收到多少。它只是分配一个缓冲区,然后 API 将向其中写入数据。
  • @kenny-kerr 你能添加 std::unique_ptr 构造函数到array_view吗?像:cpp template &lt;typename C&gt; array_view(std::unique_ptr&lt;C[]&gt; const&amp; value, size_type size) noexcept : array_view(value.get(), size) {} 这样我就可以像这样使用它:cpp std::unique_ptr&lt;bool[]&gt; buttonsArray = std::make_unique&lt;bool[]&gt;(buttons); uint64_t timestamp = rawController.GetCurrentReading({ buttonsArray, buttons }, switchesArray, axisArray); ?
  • 您始终可以创建自定义缓冲区并传递一对开始/结束指针/迭代器。
【解决方案2】:

std::vector&lt;bool&gt; 中的每个元素占用一个位而不是 sizeof(bool) 字节。它不一定将其元素存储为连续数组,因此不包含 data() 方法。我有一个工作代码,但是这不是最佳解决方案。您可以尝试使用 bool b[] 方法创建 bool 数组。

bool buttonsArray[]{ rawController.ButtonCount(), false };
std::vector<GameControllerSwitchPosition> switchesArray(rawController.SwitchCount(), GameControllerSwitchPosition::Center);
std::vector<double> axisArray(rawController.AxisCount(), 0.0);
uint64_t timestamp = rawController.GetCurrentReading(buttonsArray, switchesArray, axisArray);

【讨论】:

    【解决方案3】:

    丑陋的解决方法,而不是使用vector&lt;bool&gt;

    int32_t buttons = rawController.ButtonCount();
    int32_t switches = rawController.SwitchCount();
    int32_t axis = rawController.AxisCount();
    
    std::unique_ptr<bool[]> buttonsArray = std::make_unique<bool[]>(buttons);
    std::vector<GameControllerSwitchPosition> switchesArray(switches);
    std::vector<double> axisArray(axis);
    
    uint64_t timestamp = rawController.GetCurrentReading(winrt::array_view<bool>(buttonsArray.get(), buttonsArray.get() + buttons), switchesArray, axisArray);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多