函数中std :: initializer_list <T> :: size`上的static_assert

在单元测试中,我想要一种快速(干净的)肮脏的方式从initializer_list向静态大小的C数组分配值。我不是一个完整的野兽,所以我想static_assert大小相同。我写了一个辅助函数set_array来做到这一点:

template <typename T,std::size_t N>
constexpr void set_array(T (&x)[N],std::initializer_list<T>&& list) {
  assert(list.size() == N); // why can't I static_assert in C++17?
  for (std::size_t i = 0; i < N; ++i)
    x[i] = list.begin()[i];
}

旨在将其用作set_array(foo,{1,2,3,4});,并将foo声明为int foo[4]

我使用的是C ++ 17,所以std std::initializer_list<T>::size是constexpr,但是一旦通过函数调用传递列表,我便失去了将其视为constexpr的特权,因为我无法约束函数参数为constexpr。

感觉应该有一个我没有看到的简单解决方案。当然,我可以想象一些反常的元编程游戏,我可以玩这些游戏来将大小编码为一种类型,但这是一个简单的小帮手,应该可以使事情变得清晰易读,而且我也不想胡闹。

问题:是否有一个简单的解决方案,还是我应该只接受运行时断言? (是的,我知道,如果给我一个简单的解决方案,我会因为自己没看过而感到愚蠢。)认为我会以错误的方式处理吗?很好,我愿意接受建议,也欢迎提出批评。

详细信息: 为了完整起见,这是编译器错误和版本信息。在Clang版本8.0.0-3(Ubuntu clang-8随附)中,我得到:

error: static_assert expression is not an
      integral constant expression
  static_assert(list.size() == N);
                ^~~~~~~~~~~~~~~~

在GCC 8.3.0中,我遇到了类似的错误,另外还告诉我list不是常量表达式。

nihaoxiaoguo 回答:函数中std :: initializer_list <T> :: size`上的static_assert

函数的参数不是常量。

这在C ++中是合法的:

void foo( bool which ) {
  std::initializer_list<int> a = {1,2,3};
  std::initializer_list<int> b = {1,3,4};
  int x[4];
  std::initializer_list<int> c = which?a:b;    
  set_array(x,c);
}

尝试一下:

template<class T>
struct block_deduction_t{using type=T;};
template<class T>
using block_deduction = typename block_deduction_t<T>::type;

template <typename T,std::size_t N>
constexpr void set_array(T (&x)[N],block_deduction<T const(&)[N]> list) {
   for (std::size_t i = 0; i < N; ++i)
      x[i] = list[i];
}

现在,这允许您省略尾随元素,但是它们将被零初始化。

Live example

然后再次提出以下解决方案:

template <typename T,T const(&list)[N]) {
   for (std::size_t i = 0; i < N; ++i)
      x[i] = list[i];
}

实际上会挡住尺寸较小的右侧。这样可能会更好。

语法完全符合您的要求。

如果您想得到一个漂亮的错误消息,并且将右侧的类型转换为与左侧的类型相匹配:

template <typename T,std::size_t N,std::size_t M>
constexpr void set_array(T (&x)[N],block_deduction<T> const(&list)[M]) {
   static_assert(M==N,"wrong number of elements");
   for (std::size_t i = 0; i < N; ++i)
      x[i] = list[i];
}

有很多变体。

,

即使sizeconstexpr也会失败的原因是因为list不是constexpr变量,因此对其调用的任何成员函数也不会是constexpr变量。 constexpr

尽管一切都没有丢失。您可以使用std::array代替std::initializer_list,甚至可以摆脱static_assert,例如:

template <typename T,std::array<T,N>&& list) {
  for (std::size_t i = 0; i < N; ++i)
    x[i] = list[i];
}                                                          

int main()                                                                       
{                                                                                
    int arr[4];
    set_array(arr,{1,4});
    std::cout << arr[3];
}

如果您尝试使用

set_array(arr,4,5});

然后您将得到类似编译器错误

main.cpp:12:16: note: candidate function [with T = int,N = 4] not viable: cannot convert initializer list argument to 'std::array<int,4UL>'
constexpr void set_array(T (&x)[N],N>&& list) {
本文链接:https://www.f2er.com/2675246.html

大家都在问