【问题标题】:Returning a tuple containing a C-array返回包含 C 数组的元组
【发布时间】:2020-12-19 15:11:23
【问题描述】:

我有一些代码在 g++ 10.2.0 下编译和运行良好,但被 clang++ 11.0.0 拒绝。

这是该问题的最小复制器:

#include <tuple>
#include <cstdint>

struct Dummy { };

using second_t = Dummy;
using example_t = std::tuple<size_t, second_t[8]>;

example_t f() {
    example_t result;
    return result;
}

int main() {
    auto x = f();
    (void) x;
}

在 g++ 中,它编译时没有任何抱怨,但使用 clang++ 我得到:

clang++ --std=c++20 -Wall -Werror main.cpp -o example
In file included from main.cpp:1:
/usr/bin/../lib/gcc/aarch64-unknown-linux-gnu/10.2.0/../../../../include/c++/10.2.0/tuple:137:4: error: array initializer must be an initializer list
        : _M_head_impl(std::forward<_UHead>(__h)) { }
          ^
/usr/bin/../lib/gcc/aarch64-unknown-linux-gnu/10.2.0/../../../../include/c++/10.2.0/tuple:375:9: note: in instantiation of function template specialization 'std::_Head_base<1, Dummy [8], false>::_Head_base<Dummy [8]>' requested here
      : _Base(std::forward<_Head>(_M_head(__in))) { }
        ^
/usr/bin/../lib/gcc/aarch64-unknown-linux-gnu/10.2.0/../../../../include/c++/10.2.0/tuple:236:9: note: in instantiation of member function 'std::_Tuple_impl<1, Dummy [8]>::_Tuple_impl' requested here
      : _Inherited(std::move(_M_tail(__in))),
        ^
/usr/bin/../lib/gcc/aarch64-unknown-linux-gnu/10.2.0/../../../../include/c++/10.2.0/tuple:996:17: note: in instantiation of member function 'std::_Tuple_impl<0, unsigned long, Dummy [8]>::_Tuple_impl' requested here
      constexpr tuple(tuple&&) = default;
                ^
main.cpp:11:12: note: in defaulted move constructor for 'std::tuple<unsigned long, Dummy [8]>' first required here
    return result;
           ^
1 error generated.
make: *** [Makefile:2: all] Error 1

有趣的是,如果我将 second_t 更改为 int32_t,我也会收到来自 g++ 的错误:

g++ --std=c++20 -Wall -Werror main.cpp -o example
In file included from main.cpp:1:
/usr/include/c++/10.2.0/tuple: In instantiation of ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(_UHead&&) [with _UHead = int [8]; long unsigned int _Idx = 1; _Head = int [8]]’:
/usr/include/c++/10.2.0/tuple:375:49:   required from ‘constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head>&&) [with long unsigned int _Idx = 1; _Head = int [8]]’
/usr/include/c++/10.2.0/tuple:237:42:   required from ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head, _Tail ...>&&) [with long unsigned int _Idx = 0; _Head = long unsigned int; _Tail = {int [8]}]’
/usr/include/c++/10.2.0/tuple:996:17:   required from here
/usr/include/c++/10.2.0/tuple:137:42: error: array used as initializer
  137 |  : _M_head_impl(std::forward<_UHead>(__h)) { }
      |                                          ^
make: *** [Makefile:2: all] Error 1

我猜这取决于使用 C 数组。如果我将代码更改为使用std::array,问题就会消失。但是,出于好奇,我仍然很好奇是否有办法用 C-array 做到这一点。

所以我的问题是:

  1. g++ 接受此代码有误吗?
  2. 有什么方法可以在像这样适用于 g++ 和 clang++ 的元组中返回 C 数组?

【问题讨论】:

  • 根据 C++ 标准,在一个元组中有一个普通数组是否符合规定是一个很好的问题。然而,无论答案是什么:这只是其中一件不可取的事情,即使它是正确的,我也不会这样做。如果您需要元组中的数组,请使用 std::array 而不是普通数组。您不会注意到有什么不同,需要处理的意外惊喜也会减少,头痛也会减少。
  • @SamVarshavchik 虽然我同意,但我不能这样做,根据我对问题中 std::array 的评论:)
  • std::array 字面意思是template &lt;typename T, std::size_t N&gt; struct array { functions; private: T data[N]; };。如果数组对您来说是安全的,那么std::array 也是如此
  • 我认为这是因为对于元组的复制/移动构造函数:std::is_move_constructible&lt;Ti&gt;::value must be true for all i, otherwise the behavior is undefined。对于 C 数组,这是错误的,所以我们得到未定义的行为
  • 如果您不喜欢std::array,您可以随时使用struct scared_of_the_STL { second_t data[8]; };。这在 C 中很常见,具有易于复制的数组。

标签: c++ c++20 stdtuple


【解决方案1】:

C 数组基本上是指针,注意它们不提供也不需要关于数组长度的信息。长度必须分开保存并传递。因此,实现您需要的一种方法是:

  using example_t = std::tuple<size_t, second_t*>;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-27
    • 1970-01-01
    • 2012-02-05
    • 2021-10-21
    • 1970-01-01
    • 2020-12-17
    相关资源
    最近更新 更多