C++ 如何像 ac 数组一样初始化“const std::vector<T>”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/231491/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:54:46  来源:igfitidea点击:

how-to initialize 'const std::vector<T>' like a c array

c++stl

提问by vscharf

Is there an elegant way to create and initialize a const std::vector<const T>like const T a[] = { ... }to a fixed (and small) number of values?
I need to call a function frequently which expects a vector<T>, but these values will never change in my case.

有一种优雅的方式来创建和初始化const std::vector<const T>喜欢const T a[] = { ... }到固定的值(小)多少?
我需要经常调用一个需要 a 的函数vector<T>,但这些值在我的情况下永远不会改变。

In principle I thought of something like

原则上我想到了类似的东西

namespace {
  const std::vector<const T> v(??);
}

since v won't be used outside of this compilation unit.

因为 v 不会在这个编译单元之外使用。

采纳答案by Ferruccio

You either have to wait for C++0x or use something like Boost.Assignto do that.

您要么必须等待 C++0x,要么使用Boost.Assign 之类的东西来做到这一点。

e.g.:

例如:

#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope

vector<int> v;
v += 1,2,3,4,5;

for C++11:

对于 C++11:

vector<int> luggage_combo = { 1, 2, 3, 4, 5 };

回答by Steve Jessop

If you're asking how to initialise a const vector so that it has interesting contents, then the answer is probably to use the copy constructor. First you laboriously fill in a vector, then you create your new const vector from it. Or you can use the vector<InputIterator>(InputIterator, InputIterator) constructor template to initialise from some other kind of container or an array. If an array, then that could have been defined with an initialisation list.

如果您问如何初始化 const 向量以使其具有有趣的内容,那么答案可能是使用复制构造函数。首先,您费力地填充一个向量,然后从中创建新的 const 向量。或者,您可以使用 vector<InputIterator>(InputIterator, InputIterator) 构造函数模板从其他类型的容器或数组进行初始化。如果是数组,则可以使用初始化列表定义它。

Something like this is hopefully close to what you want:

像这样的东西希望接近你想要的:

const T ra[3] = {t1, t2, t3};
const vector<const T> v(ra, ra+3);

If you're asking how to pass a const vector into a function which takes a vector then the answer is either:

如果您要问如何将常量向量传递给采用向量的函数,那么答案是:

  • you can't, because the function might alter the vector and your object/reference is const. Make a non-const copy of the original, and pass that in.
  • 你不能,因为函数可能会改变向量,而你的对象/引用是常量。制作原始文件的非常量副本,然后将其传入。

or

或者

  • use const_cast to remove the constness in order to pass it into a function which takes a non-const vector but which you just so happen to know will not modify the vector.
  • 使用 const_cast 删除常量,以便将其传递给一个函数,该函数采用非常量向量,但您碰巧知道它不会修改向量。

The latter is one of those things which will, quite rightly, cause anyone who sees it to make comments about goggles, and the fact that they do nothing. It's exactly what const_cast is for, but there's a reasonably strong argument that says if you need const_cast, you have already lost.

后者是其中之一,完全正确地会导致任何看到它的人对护目镜发表评论,以及他们什么都不做的事实。这正是 const_cast 的用途,但有一个相当有力的论据表明,如果您需要 const_cast,那么您已经输了。

Doing both of those things (creating a const vector from a non-const one with the copy constructor, and then casting away constness) is definitely wrong - you should have just used a non-const vector. So pick at most one of these to do...

做这两件事(使用复制构造函数从非常量向量创建一个常量向量,然后抛弃常量)绝对是错误的——你应该只使用一个非常量向量。所以最多选择其中一个来做......

[Edit: just noticed that you're talking about a difference between vector<T> and const vector<const T>. Unfortunately in the STL, vector<const T> and vector<T> are completely unrelated types, and the only way to convert between them is by copying. This is a difference between vectors and arrays - a T** can be silently and safely converted to const T *const *]

[编辑:刚刚注意到您在谈论 vector<T> 和 const vector<const T> 之间的区别。不幸的是,在 STL 中,vector<const T> 和 vector<T> 是完全不相关的类型,在它们之间进行转换的唯一方法是通过复制。这是向量和数组之间的区别 - T** 可以静默且安全地转换为 const T *const *]

回答by Shadow2531

Short and dirty way (similar to Boost's list_of())

简短而肮脏的方式(类似于 Boost 的 list_of())


#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;

template <typename T>
struct vlist_of : public vector<T> {
    vlist_of(const T& t) {
        (*this)(t);
    }
    vlist_of& operator()(const T& t) {
        this->push_back(t);
        return *this;
    }
};

int main() {
    const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5);
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\n"));
}

Now, C++11 has initializer lists, so you don't need to do it that way or even use Boost. But, as an example, you can do the above in C++11 more efficiently like this:

现在,C++11 有初始化列表,所以你不需要那样做,甚至不需要使用 Boost。但是,例如,您可以像这样在 C++11 中更有效地执行上述操作:

#include <iostream>
#include <vector>
#include <utility>
#include <ostream>
using namespace std;

template <typename T>
struct vlist_of : public vector<T> {
    vlist_of(T&& t) {
        (*this)(move(t));
    }
    vlist_of& operator()(T&& t) {
        this->push_back(move(t));
        return *this;
    }
};

int main() {
    const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5);
    for (const auto& i: v) {
        cout << i << endl;
    }
}

But, it's still not as efficient as using a C++11 initializer list because there's no operator=(vlist_of&&) defined for vector.

但是,它仍然不如使用 C++11 初始值设定项列表有效,因为没有为 vector 定义 operator=(vlist_of&&) 。

tjohns20's way modified like the following might be a better c++11 vlist_of:

tjohns20 的方式修改如下可能是更好的 c++11 vlist_of:

#include <iostream>
#include <vector>
#include <utility>
using namespace std;

template <typename T>
class vlist_of {
    public:
        vlist_of(T&& r) {
            (*this)(move(r));
        }
        vlist_of& operator()(T&& r) {
            v.push_back(move(r));
            return *this;
        }
        vector<T>&& operator()() {
            return move(v);
        }
    private:
        vector<T> v;

};

int main() {
    const auto v = vlist_of<int>(1)(2)(3)(4)(5)();
    for (const auto& i : v) {
        cout << i << endl;
    }

}

回答by John Dibling

As others have said, you can't init a vector the same way you can init a C-style array, unless you give it pointers to a source array. But in that case, if your vector is a global const, why not just use an old C-style array instead?

正如其他人所说,你不能像初始化一个 C 风格的数组一样初始化一个向量,除非你给它一个指向源数组的指针。但是在那种情况下,如果您的向量是全局常量,为什么不使用旧的 C 样式数组呢?

const int MyInts[] = {
1, 2, 3, 4, 5};

const size_t NumMyInts = sizeof(MyInts)/sizeof(MyInts[0]);

You can even use STL algorithms against this array, the same way you would use algorithms against a const vector...

您甚至可以对这个数组使用 STL 算法,就像对 const 向量使用算法一样......

const int* myInt = std::find( &MyInts[0], &MyInts[NumMyInts], 3);

回答by janm

You can do it in two steps:

您可以分两步完成:

namespace {
    const T s_actual_array[] = { ... };
    const std::vector<const T> s_blah(s_actual_array,
        s_actual_array + (sizeof(s_actual_array) / sizeof(s_actual_array[0])));
}

Perhaps not as beautiful as you might like, but functional.

也许没有你喜欢的那么漂亮,但实用。

回答by opal

How about:

怎么样:

int ar[]={1,2,3,4,5,6};
const int TotalItems = sizeof(ar)/sizeof(ar[0]);
std::vector<int> v(ar, ar+TotalItems);

回答by Kevin

Old question, but I ran into the same issue today, here's the approach that was most acceptable for my purposes:

老问题,但我今天遇到了同样的问题,这是我的目的最可接受的方法:

vector<int> initVector(void)
{
    vector<int> initializer;
    initializer.push_back(10);
    initializer.push_back(13);
    initializer.push_back(3);
    return intializer;
}

int main()
{
    const vector<int> a = initVector();
    return 0;
}

Example to avoid excessive copying:

避免过度复制的示例:

vector<int> & initVector(void)
{
    static vector<int> initializer;
    if(initializer.empty())
    {
        initializer.push_back(10);
        initializer.push_back(13);
        initializer.push_back(3);
    }
    return intializer;
}

int main()
{
    const vector<int> & a = initVector();
    return 0;
}

回答by Peter

If they're all the same you can just do

如果他们都一样,你可以做

vector<T> vec(num_items, item);

but I assume they're not - in which case the neatest way is probably:

但我认为它们不是 - 在这种情况下,最简洁的方法可能是:

vector<T> vec(num_items);
vec[0] = 15;
vec[1] = 5;
...

C++0x will let you use an initialiser list in exactly the way you're thinking of, but that's not a lot of good right now, unfortunately.

C++0x 将让您完全按照您的想法使用初始化列表,但不幸的是,现在这不是很好。

回答by tjohns20

Based on Shadow2531's response, I'm using this class to initialise vectors, without actually inheriting from std::vector like Shadow's solution did

基于 Shadow2531 的响应,我使用这个类来初始化向量,而不是像 Shadow 的解决方案那样从 std::vector 实际继承

template <typename T>
class vector_init
{
public:
    vector_init(const T& val)
    {
        vec.push_back(val);
    }
    inline vector_init& operator()(T val)
    {
        vec.push_back(val);
        return *this;
    }
    inline std::vector<T> end()
    {
        return vec;
    }
private:
    std::vector<T> vec;
};

Usage:

用法:

std::vector<int> testVec = vector_init<int>(1)(2)(3)(4)(5).end();

Compared to Steve Jessop's solution it creates a lot more code, but if the array creation isn't performance critical I find it a nice way to initialise an array in a single line

与 Steve Jessop 的解决方案相比,它创建了更多的代码,但如果数组创建不是性能关键,我发现这是在一行中初始化数组的好方法

回答by mstrobl

Not sure if I understood you right. I understand your question like this: you want to initialize a vector to a large number of elements. What's wrong with using push_back() on the vector? :-)

不确定我是否理解你的意思。我理解你的问题是这样的:你想将一个向量初始化为大量元素。在向量上使用 push_back() 有什么问题?:-)

If you know the number of elements to be stored (or are sure that it will store less than the next power of 2) you can do this, if you have a vector of pointers of type X (works only with pointers):

如果您知道要存储的元素数量(或者确定它存储的元素数小于 2 的下一次幂),则可以执行此操作,前提是您有 X 类型的指针向量(仅适用于指针):

std::vector< X* > v;
v.reserve(num_elems);
X* p = v.begin();
for (int count = 0; count < num_elems; count++)
   p[count] = some_source[count];

Beware of adding more than the next power of 2 elements, even if using push_back(). Pointers to v.begin() will then be invalid.

即使使用 push_back(),也要注意添加超过 2 的下一个幂的元素。指向 v.begin() 的指针将无效。