【问题标题】:Passing primitive array to function with std::initializer_list argument使用 std::initializer_list 参数将原始数组传递给函数
【发布时间】:2012-12-06 07:20:55
【问题描述】:

使用以 std::initializer_list 作为参数的函数,如下所示

int sumOf(std::initializer_list<int> numbers) {
    int sum = 0;  
    for (auto x : numbers) {
        sum += x;
    }
    return sum;
}

此代码有效

auto sum = sumOf({ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

但不是这个

 int i[]  = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 auto x = sumOf(i);

为什么第二种形式不起作用?还是我做错了什么?

编辑:
从 std::intializer_list 的 gcc 4.7.2 实现来看, intializer_list 的构造函数是私有的,编译器需要传递数组的大小。

  // The compiler can call a private constructor.
  constexpr initializer_list(const_iterator __a, size_type __l)
  : _M_array(__a), _M_len(__l) { }

我猜编译器在某些情况下无法从变量“i”判断数组的大小。如果是这样,编译器不支持将静态数组传递给 intializer_list (?)。

【问题讨论】:

  • 但是{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } 确实创建了std::initializer_list
  • 好吧,一个传递一个初始化列表,除了函数之外,另一个传递一个数组,还有什么应该发生的。初始化列表不仅仅是一个数组。将其更改为auto i = { ... }; 怎么样,但不确定这是否有效。
  • @ChristianRau - 它适用于 auto i = { ... };,但 "i" 似乎不再表现为 int 数组。
  • @KiranMohan 不,因为现在是std::initializer_list,这是函数所期望的类型,与数组完全不同。

标签: c++ c++11 initializer-list


【解决方案1】:

i 不是initializer_listinitializer_list 不是“静态数组”的简写。这是一个特殊对象,只能通过使用花括号初始化列表(即:{...} 语法)创建(在复制构造之外)。

当您执行int i[] = {...}; 时,您正在对一个数组 执行聚合初始化。 iints 的数组,而不是 initializer_list

你想要的是一个模板函数,它可以接受任何你可以使用的基于范围的函数:

template<typename Rng>
int sumOf(const Rng &numberRange) {
    int sum = 0;  
    for (auto x : numberRange) {
        sum += x;
    }
    return sum;
}

【讨论】:

  • 模板版本在使用{...} 语法直接传递值时不起作用,除非您有采用 std::initializer_list 的 sumOf() 专用版本
  • @KiranMohan:目前,这是正确的,也是auto 与普通模板参数推导之间的唯一差异。不过,有人提议在 C++Next 中修复这个问题。
【解决方案2】:

您可以使用索引元组技巧,就像许多人之前使用的那样

template<int N, int ...X>
struct I : struct I<N-1, N, X...> {};

template<int X...>
struct I<0, X...> {
  typedef I type;
};

template<typename F, typename T, int N, int ...X>
decltype(f(std::declval<std::initializer_list<T>>()))
make_list(T const (&a)[N], F f, I<X...>) 
{
   return f(std::initializer_list<T>{a[X]...});
}

template<typename F, typename T, int N>
decltype(f(std::declval<std::initializer_list<T>>()))
make_list(T const(&a)[N], F f) {
   return make_list(a, f, typename I<N-1>::type());
}

使用简单

make_list(i, &sumOf);

或者使用 lambda

make_list(i, [](std::initializer_list<int> x) {
  return sumOf(x);
});

【讨论】:

    猜你喜欢
    • 2022-07-06
    • 2012-11-25
    • 1970-01-01
    • 2018-12-23
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多