std::initializer_list and reference types

15

std::initializer_list能否包含引用类型(rvalue和lvalue)?还是必须使用指针或引用包装器(例如std::ref)?

编辑:

也许需要更多的解释:

我有一个成员变量,类型为::std::vector<std::function<void()> >,我想将lambda对象转发到其中。这通常可以使用emplace_back来完成,但我想在构造函数的初始化列表中完成它。然而,据我所读,这会使转发变得不可能。


1
你的意思是类似于 std::initializer_list<int&> a = {...}; 这样的吗? - R Sahu
@RSahu 是的,或者 &&,但我主要考虑的是类引用类型。 - user1095108
3个回答

13

std::initializer_list<T> 装载的元素不包含引用类型(无论是右值引用还是左值引用)。它使用拷贝语义,将其值以const对象的形式储存:

18.9 Initializer List [support.initlist]

类型为initializer_list<E>的对象提供对一组const E对象的访问。

如果使用引用类型的 initializer_list 将会导致编译错误,因为迭代器内部使用指针实现:

#include <initializer_list>
int main()
{
    int x;
    std::initializer_list<int&> l = {x};

    // In instantiation of 'class std::initializer_list<int&>':
    // error: forming pointer to reference type 'int&'

    // typedef const _E*  iterator;
}

initializer_list 不支持移动语义,因为 const 对象不可移动。如果您希望保持引用语义,则在 std::reference_wrapper<T> 中保存对象是最可行的解决方案。


我相信它们支持某种移动语义,因为你在技术上可以“移动”一个const && - user1095108
1
@user1095108不会。通过调用std::move()并不能实现移动,它只是将其转换为右值。当一个构造函数采用非const rvalue引用 (X&&) 时,才真正地发生移动操作,而移动一个const对象在某些情况下实际上会创建一个副本,在其他情况下则会导致编译错误。 - David G
1
我知道,但是没有什么能阻止移动构造函数复制而不是移动。我只是在挑刺。 - user1095108

8

那么,我需要使用包装器还是指针? - user1095108
我会说是的,一些你可以分配一个数组的东西。 - Marco A.

2

这里不需要列表初始化

正如其他人所提到的,您不能在引用中使用std::initializer_list。您可以使用std::initializer_list<std::reference_wrapper<...>>,但它将阻止您将rvalue作为参数传递给构造函数,因为std::reference_wrapper只能绑定到lvalue。换句话说,以下代码将无法编译:

YourContainerOfFunctions C{ [](){} };

在您的情况下,使用 std::initializer_list 既不高效也不方便。

使用可变模板代替!

我相信这就是您想要实现的:

class Foo {
  std::vector<std::function<void()>> Functions;

public:
  template <class... FuncTs>
  Foo(FuncTs &&...Funcs) : Functions({std::forward<FuncTs>(Funcs)...}) {}
};

void foo(){};

int main() {
  auto boo = []() {};
  std::function<void()> moo = []() {};

  Foo F{
      foo, boo,      // passed by reference, then copied
      []() {},       // moved, then copied
      std::move(moo) // moved, then also moved
  };
}

每个参数最多需要一份副本,这是必要的,因为std::function总是会复制从中构造的函数对象。一个例外是使用相同类型的std::function构造std::function


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接