为什么不能用括号括起来的初始化程序列表构造gsl :: span [英] Why can't I construct a gsl::span with a brace-enclosed initializer list

查看:84
本文介绍了为什么不能用括号括起来的初始化程序列表构造gsl :: span的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 C ++核心指南,我应该使用gsl :: span传递半开序列.

我认为这意味着不要编写像这样的函数:

I think that means that instead of writing a function like:

void func(const std::vector<int>& data) {
    for (auto v : data) std::cout << v << " ";
}

我应该喜欢:

void func(gsl::span<const int> data) {
    for (auto v : data) std::cout << v << " ";
}

其优点在于,它不假定调用方将其数据存储在 vector 中,也不强制调用方构造临时的 vector .例如,他们可以传递 std :: array .

Which has the advantage that it does not assume the caller has their data in a vector, or force them to construct a temporary vector. They could pass a std::array for example.

但是一个常见的用例是传递一个用大括号括起来的初始化器列表:

But a common use-case is to pass a brace-enclosed initializer list:

func({0,1,2,3})

这对于采用 std :: vector 的函数有效,但对于采用 gsl :: span 的函数,我会收到错误消息:

This works for a function taking a std::vector but for a function taking a gsl::span I get the error message:

错误C2664:'void func(gsl :: span)':无法转换从'initializer-list'到'gsl :: span'的参数1

error C2664: 'void func(gsl::span)' : cannot convert argument 1 from 'initializer-list' to 'gsl::span'

它看起来像 gsl :: span 有一个模板化的构造函数,用于接收任何容器.

It looks like gsl::span has a templated constructor designed to take any container.

这只是Microsoft GSL实施中缺少的东西吗?还是有充分的理由阻止这种做法?

Is this just something missing from the Microsoft GSL implementation or is there a good reason to prevent this practice?

推荐答案

调用矢量版本时,初始化程序列表用于创建临时的 std :: vector ,然后将其传递给通过const引用的功能.这是可能的,因为 std :: vector 具有一个构造函数,该构造函数将 std :: initializer_list< T> 作为参数.但是, gsl :: span 没有这样的构造函数,并且 {0,1,2,3} 没有类型,它也不能被您提到的模板化构造函数接受(除了事实, std :: initializer_list< T> 仍然不能满足容器的概念.

When you call the vector version, the initializer list is used to create a temporary std::vector, which is then passed to the function by const reference. This is possible, because std::vector has a constructor, that takes an std::initializer_list<T> as an argument.
However, gsl::span doesn't have such a constructor and as {0,1,2,3} doesn't have a type, it also can't be accepted by the templated constructor you mentioned (besides the fact, that std::initializer_list<T> wouldn't satisfy the container concept anyway).

一个(丑陋的)解决方法当然是显式创建一个临时数组:

One (ugly) workaround would be of course to explicitly create a temporary array:

func(std::array<int,4>{ 0,1,2,3 });

我没有看到特定的原因,为什么 gsl :: span 不应具有采用 std :: initializer_list 的构造函数,但是请记住,该库仍处于新的阶段,并且正在积极开发中.因此,也许是他们忽略了这些东西,没有时间实施,不确定如何正确执行操作或确实存在一些细节,这会使该构造变得危险.最好直接在github上询问开发人员.

I don't see a particular reason, why gsl::span should not have a constructor that takes a std::initializer_list, but keep in mind that this library is in still pretty new and under active development. So maybe it is something they overlooked, didn't have time to implement, weren't sure how to do properly or there are really some details, that would make that construct dangerous. Its probably best to ask the developers directly on github.


正如@Nicol Bolas在他的评论中解释的那样,这是设计的原因,因为初始化列表类似于 {0,1,2,3} (及其中的元素)是一个临时对象,并且 gsl :: span 本身并不是一个容器(它没有"),他们认为意外地创建一个 gsl :: span ,其中包含对这些临时元素的悬挂引用会很容易.


As @Nicol Bolas explains in his comment, this was by design because an initializer list like {0,1,2,3} (and the elements within) is a temporary object and as gsl::span is not a container in its own right (it doesn't take ownership of the elements), they think it would be too easy to accidentally create a gsl::span that contains a dangling reference to those temporary elements.

所以,这没关系:

func({ 0,1,2,3 });

由于初始化器列表的生存期在函数完成后结束,因此将创建一个悬空的引用:

because the lifetime of the initializer list ends after the completion of the function, something like this would create a dangling reference:

gsl::span<const int> data{ 0,1,2,3 };
func(data);

这篇关于为什么不能用括号括起来的初始化程序列表构造gsl :: span的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆