Каков самый простой способ инициализации std:: vector с жестко закодированными элементами?
Я могу создать массив и инициализировать его, как это:
int a[] = {10, 20, 30};
как мне создать std::vector и инициализировать его так же элегантно?
лучший способ, который я знаю, это:
std::vector<int> ints;
ints.push_back(10);
ints.push_back(20);
ints.push_back(30);
есть ли лучший способ?
25 ответов:
один из методов будет использовать массив для инициализации вектора
static const int arr[] = {16,2,77,29}; vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );
если ваш компилятор поддерживает C++11, вы можете просто сделать:
std::vector<int> v = {1, 2, 3, 4};это доступно в GCC начиная с версии 4.4. К сожалению, VC++ 2010, похоже, отстает в этом отношении.
кроме того,импульс.Назначить библиотека использует не-макро магию, чтобы позволить следующее:
#include <boost/assign/list_of.hpp> ... std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);или:
#include <boost/assign/std/vector.hpp> using namespace boost::assign; ... std::vector<int> v; v += 1, 2, 3, 4;но имейте в виду, что это имеет некоторые накладные расходы (в основном,
list_ofсоздаетstd::dequeпод капотом) поэтому для критичного к производительности кода вам лучше делать так, как говорит Якоби.
В C++0x вы сможете сделать это так же, как вы сделали с массивом, но не в текущем стандарте.
С поддержкой только языка вы можете использовать:
int tmp[] = { 10, 20, 30 }; std::vector<int> v( tmp, tmp+3 ); // use some utility to avoid hardcoding the size hereЕсли вы можете добавить другие библиотеки, вы можете попробовать boost:: assignment:
vector<int> v = list_of(10)(20)(30);чтобы избежать жесткого кодирования размера массива:
// option 1, typesafe, not a compile time constant template <typename T, std::size_t N> inline std::size_t size_of_array( T (&)[N] ) { return N; } // option 2, not typesafe, compile time constant #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) // option 3, typesafe, compile time constant template <typename T, std::size_t N> char (&sizeof_array( T(&)[N] ))[N]; // declared, undefined #define ARRAY_SIZE(x) sizeof(sizeof_array(x))
просто подумал, что я брошу свои $ 0.02. Я склонен заявить следующее:
template< typename T, size_t N > std::vector<T> makeVector( const T (&data)[N] ) { return std::vector<T>(data, data+N); }в заголовке утилиты где-то, а затем все, что требуется, это:
const double values[] = { 2.0, 1.0, 42.0, -7 }; std::vector<double> array = makeVector(values);но я не могу ждать для C++0х. Я застрял, потому что мой код должен компилироваться в Visual студии. Освистывать.
В C++11:
#include <vector> using std::vector; ... vector<int> vec1 { 10, 20, 30 }; // or vector<int> vec2 = { 10, 20, 30 };С помощью boost list_of:
#include <vector> #include <boost/assign/list_of.hpp> using std::vector; ... vector<int> vec = boost::assign::list_of(10)(20)(30);С помощью boost назначить:
#include <vector> #include <boost/assign/std/vector.hpp> using std::vector; ... vector<int> vec; vec += 10, 20, 30;обычный STL:
#include <vector> using std::vector; ... static const int arr[] = {10,20,30}; vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );обычный STL с общими макросами:
#include <vector> #define ARRAY_SIZE(ar) (sizeof(ar) / sizeof(ar[0]) #define ARRAY_END(ar) (ar + ARRAY_SIZE(ar)) using std::vector; ... static const int arr[] = {10,20,30}; vector<int> vec (arr, ARRAY_END(arr));обычный STL с макросом векторного инициализатора:
#include <vector> #define INIT_FROM_ARRAY(ar) (ar, ar + sizeof(ar) / sizeof(ar[0]) using std::vector; ... static const int arr[] = {10,20,30}; vector<int> vec INIT_FROM_ARRAY(arr);
ради Бога, используйте современный C++[11,14,17,...] путь:
std::vector<int> vec = {10,20,30};старый способ циклического перебора массива переменной длины или использования
sizeof()действительно ужасно на глазах и совершенно ненужно с точки зрения умственных накладных расходов. Фу.
Перед C++ 11:
Способ 1=>
vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0])); vector<int>v;Способ 2 =>
v.push_back(SomeValue);C++ 11 далее также возможно
vector<int>v = {1, 3, 5, 7};
начиная с:
int a[] = {10, 20, 30}; //i'm assuming a is just a placeholderесли у вас нет компилятора C++11, и вы не хотите использовать boost:
const int a[] = {10, 20, 30}; const std::vector<int> ints(a,a+sizeof(a)/sizeof(int)); //make it const if you canесли у вас нет компилятора C++11 и можете использовать boost:
#include <boost/assign.hpp> const std::vector<int> ints = boost::assign::list_of(10)(20)(30);если у вас есть компилятор C++11:
const std::vector<int> ints = {10,20,30};
для вектора инициализации -
vector<int> v = {10,20,30}можно сделать, если у вас есть компилятор C++11.
другое, вы можете иметь массив данных, а затем использовать цикл for.
int array[] = {10,20,30} for(int i=0; i<sizeof(array); i++) v.push_back(array[i]);помимо этого, существуют различные другие способы, описанные выше, используя некоторый код. На мой взгляд, эти способы легко запомнить и быстро записать.
Если ваш компилятор поддерживает вариативную макрос (что верно для большинства современных компиляторов), то вы можете использовать следующий макрос для поворота вектора инициализации в один-лайнер:
#define INIT_VECTOR(type, name, ...) \ static const type name##_a[] = __VA_ARGS__; \ vector<type> name(name##_a, name##_a + sizeof(name##_a) / sizeof(*name##_a))С помощью этого макроса вы можете определить инициализированный вектор с таким кодом:
INIT_VECTOR(int, my_vector, {1, 2, 3, 4});это создаст новый вектор ints с именем my_vector с элементами 1, 2, 3, 4.
Если вы не хотите использовать boost, но хотите наслаждаться синтаксисом, как
std::vector<int> v; v+=1,2,3,4,5;просто включите этот кусок кода
template <class T> class vector_inserter{ public: std::vector<T>& v; vector_inserter(std::vector<T>& v):v(v){} vector_inserter& operator,(const T& val){v.push_back(val);return *this;} }; template <class T> vector_inserter<T> operator+=(std::vector<T>& v,const T& x){ return vector_inserter<T>(v),x; }
Я создаю свое собственное решение с помощью
va_arg. Это решение совместимо с C98.#include <cstdarg> #include <iostream> #include <vector> template <typename T> std::vector<T> initVector (int len, ...) { std::vector<T> v; va_list vl; va_start(vl, len); for (int i = 0; i < len; ++i) v.push_back(va_arg(vl, T)); va_end(vl); return v; } int main () { std::vector<int> v = initVector<int> (7,702,422,631,834,892,104,772); for (std::vector<int>::const_iterator it = v.begin() ; it != v.end(); ++it) std::cout << *it << std::endl; return 0; }
более поздний дубликат вопроса имеет ответ by Виктор Зер. Для меня он компактен, визуально привлекателен (похоже, что вы "запихиваете" значения), не требует c++11 или стороннего модуля и избегает использования дополнительной (письменной) переменной. Ниже показано, как я использую его с несколькими изменениями. Я могу переключиться на расширение функции vector и / или va_arg в будущем intead.
// Based on answer by "Viktor Sehr" on Stack Overflow // https://stackoverflow.com/a/8907356 // template <typename T> class mkvec { public: typedef mkvec<T> my_type; my_type& operator<< (const T& val) { data_.push_back(val); return *this; } my_type& operator<< (const std::vector<T>& inVector) { this->data_.reserve(this->data_.size() + inVector.size()); this->data_.insert(this->data_.end(), inVector.begin(), inVector.end()); return *this; } operator std::vector<T>() const { return data_; } private: std::vector<T> data_; }; std::vector<int32_t> vec1; std::vector<int32_t> vec2; vec1 = mkvec<int32_t>() << 5 << 8 << 19 << 79; // vec1 = (5,8,19,79) vec2 = mkvec<int32_t>() << 1 << 2 << 3 << vec1 << 10 << 11 << 12; // vec2 = (1,2,3,5,8,19,79,10,11,12)
ниже методы могут быть использованы для инициализации вектора в C++.
int arr[] = {1, 3, 5, 6}; vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
vector<int>v; v.push_back(1); v.push_back(2); v.push_back(3);и так далее
vector<int>v = {1, 3, 5, 7};третий разрешен только в C++11 и далее.
Если вы хотите что-то в том же общем порядке, что и Boost::assign без создания зависимости от Boost, следующее, По крайней мере, смутно похоже:
template<class T> class make_vector { std::vector<T> data; public: make_vector(T const &val) { data.push_back(val); } make_vector<T> &operator,(T const &t) { data.push_back(t); return *this; } operator std::vector<T>() { return data; } }; template<class T> make_vector<T> makeVect(T const &t) { return make_vector<T>(t); }хотя я хочу, чтобы синтаксис для его использования был чище, это все еще не особенно ужасно:
std::vector<int> x = (makeVect(1), 2, 3, 4);
typedef std::vector<int> arr; arr a {10, 20, 30}; // This would be how you initialize while definingдля компиляции использовать:
clang++ -std=c++11 -stdlib=libc++ <filename.cpp>
здесь есть много хороших ответов, но так как я самостоятельно пришел к своему собственному, прежде чем читать это, я решил, что все равно брошу свой здесь...
вот метод, который я использую для этого, который будет работать универсально через компиляторы и платформы:
создать структуру или класс в качестве контейнера для сбора объектов. Определим функцию перегрузки оператора
class MyObject; struct MyObjectList { std::list<MyObject> objects; MyObjectList& operator<<( const MyObject o ) { objects.push_back( o ); return *this; } };вы можете создавать функции, которые принимают структуру в качестве параметра, например:
someFunc( MyObjectList &objects );затем вы можете вызвать эту функцию, например:
someFunc( MyObjectList() << MyObject(1) << MyObject(2) << MyObject(3) );таким образом, вы можете построить и передать динамически размерную коллекцию объектов в функцию в одной чистой строке!
// Before C++11 // I used following methods: // 1. int A[] = {10, 20, 30}; // original array A unsigned sizeOfA = sizeof(A)/sizeof(A[0]); // calculate the number of elements // declare vector vArrayA, std::vector<int> vArrayA(sizeOfA); // make room for all // array A integers // and initialize them to 0 for(unsigned i=0; i<sizeOfA; i++) vArrayA[i] = A[i]; // initialize vector vArrayA //2. int B[] = {40, 50, 60, 70}; // original array B std::vector<int> vArrayB; // declare vector vArrayB for (unsigned i=0; i<sizeof(B)/sizeof(B[0]); i++) vArrayB.push_back(B[i]); // initialize vArrayB //3. int C[] = {1, 2, 3, 4}; // original array C std::vector<int> vArrayC; // create an empty vector vArrayC vArrayC.resize(sizeof(C)/sizeof(C[0])); // enlarging the number of // contained elements for (unsigned i=0; i<sizeof(C)/sizeof(C[0]); i++) vArrayC.at(i) = C[i]; // initialize vArrayC // A Note: // Above methods will work well for complex arrays // with structures as its elements.
если массив является:
int arr[] = {1, 2, 3}; int len = (sizeof(arr)/sizeof(arr[0])); // finding length of array vector < int > v; std:: v.assign(arr, arr+len); // assigning elements from array to vector
" как создать вектор STL и инициализировать его, как описано выше? Каков наилучший способ сделать это с минимальными усилиями по набору текста?"
самый простой способ инициализировать вектор, как вы инициализировали свой встроенный массив, - это использовать список инициализаторов , который был введен в C++11.
// Initializing a vector that holds 2 elements of type int. Initializing: std::vector<int> ivec = {10, 20}; // The push_back function is more of a form of assignment with the exception of course //that it doesn't obliterate the value of the object it's being called on. Assigning ivec.push_back(30);ivec-это 3 элемента в размере после присвоения (помеченный оператор) выполняется.
связанный, вы можете использовать следующее, Если вы хотите, чтобы вектор был полностью готов к быстрой инструкции (например, сразу переход к другой функции):
#define VECTOR(first,...) \ ([](){ \ static const decltype(first) arr[] = { first,__VA_ARGS__ }; \ std::vector<decltype(first)> ret(arr, arr + sizeof(arr) / sizeof(*arr)); \ return ret;})()пример
template<typename T> void test(std::vector<T>& values) { for(T value : values) std::cout<<value<<std::endl; }пример использования
test(VECTOR(1.2f,2,3,4,5,6));хотя будьте осторожны с decltype, убедитесь, что первое значение явно то, что вы хотите.
B. Stroustrup описывает хороший способ цепочки операций в 16.2.10 Selfreference на странице 464 в C++11 издание прог. Ленг. где функция возвращает ссылку, здесь изменяется на вектор. Таким образом, вы можете, как
v.pb(1).pb(2).pb(3);но может быть слишком много работы для такой небольшой прибыли.#include <iostream> #include <vector> template<typename T> class chain { private: std::vector<T> _v; public: chain& pb(T a) { _v.push_back(a); return *this; }; std::vector<T> get() { return _v; }; }; using namespace std; int main(int argc, char const *argv[]) { chain<int> v{}; v.pb(1).pb(2).pb(3); for (auto& i : v.get()) { cout << i << endl; } return 0; }1
2
3
Comments