2015-01-22 6 views
4

Я бы подумал, что можно это сделать? Но, похоже, это не так. Зачем? Или я делаю что-то неправильно?Невозможно преобразовать std :: vector <T> в std :: initializer_list <T>?

#include <vector> 
#include <initializer_list> 
#include <iostream> 

using namespace std; 

void fn(std::initializer_list<int> i) 
{ 
    for(int ivalue:i) 
    { 
    cout << ivalue << endl; 
    } 
} 

int main() 
{ 
    fn({1,2,3}); 
    fn(vector<int>{4,5,6}) 
    return 0; 
} 

demo

Я спрашиваю это потому, что у меня есть класс, который принимает список инициализации, и я производный от него, но нужно массировать список инициализатора до передачи его на базу. Как я могу это сделать?

+2

Вектор не initializer_list. Тем не менее, оба являются диапазонами, вы можете использовать begin/end или для циклов на обоих и совместно использовать код таким образом. –

+0

Да, я знаю, что вектор не является списком инициализаторов, но угрюмым он является конвертируемым? – Adrian

+2

нет это нет (можно сменить). И этого не должно быть. 'initializer_list' был создан так, чтобы контейнеры, такие как вектор, создавались из них, а не наоборот. – bolov

ответ

2

Иногда старые способы являются лучшими способами: просто передать в диапазоне:

void fn(std::initializer_list<int> i) { 
    fn(i.begin(), i.end()); 
} 

template <typename It> 
void fn(It it, It end) { 
    for (; it != end; ++it) { 
     std::cout << *it << std::endl; 
    } 
} 

fn({1, 2, 3}); 

std::vector<int> v{1, 2, 3}; 
fn(std::begin(v), std::end(v)); 

Для вашего конкретного вопроса ... Ваш конструктор, который принимает список инициализатора должен перебрать это в любом случае, просто делегат, работа с конструктором пары итераторов:

Foo(std::initializer_list<T> init) 
: Foo(init.begin(), init.end()) 
{ } 

template <typename It> 
Foo(It it, It end) 
{ 
    // here the magic happens 
} 
+0

Вы также можете передать диапазон «нового стиля», не нужно разделить на пару итераторов. Таким образом, тело 'fn' можно сохранить как в OP. –

+1

@MarcGlisse Что это за новый стиль, о котором вы говорите? – Adrian

+1

'template void fn (R const & r) {для (auto value: r) cout << значение << endl;}' –

0

В C++ отсутствует простой класс «вид в непрерывный блок памяти». Вот один:

template<class T> 
struct ro_array_view { 
    T const* b_ = nullptr; 
    T const* e_ = nullptr; 
    size_t size() const { return end()-begin(); } 
    T const* begin() const { return b_; } 
    T const* end() const { return e_; } 
    T const& operator[](size_t i)const{ return begin()[i]; } 
    bool empty()const{return begin()==end();} 
    T const& front() const { return *begin(); } 
    T const& back() const { return *std::prev(end()); } 

    // annoying numbers of constructors: 
    struct from_container_tag {}; 
    template<class O> 
    ro_array_view(from_container_tag, O&& o): 
    ro_array_view(o.data(), o.size()) {} 

    template<class...A> 
    ro_array_view(std::vector<T,A...> const& o) 
    :ro_array_view(from_container_tag{},o) {} 
    ro_array_view(std::initializer_list<T> const& il) 
    :ro_array_view(il.begin(), il.size()) {} 
    template<size_t N> 
    ro_array_view(std::array<T, N> const& o) 
    :ro_array_view(from_container_tag{},o) {} 
    template<size_t N> 
    ro_array_view(std::array<T const, N> const& o) 
    :ro_array_view(from_container_tag{},o) {} 
    template<size_t N> 
    ro_array_view(T const(&arr)[N]) 
    :array_view(arr, N) {} 

    // penultimate constructor of most paths: 
    ro_array_view(T const* arr, size_t N) 
    :ro_array_view(arr, arr+N) {} 
    // terminal constructor: 
    ro_array_view(T const* b, T const* e) 
    :b_(b),e_(e) {} 
}; 

теперь просто взять ro_array_view<int> и преобразует входящий аргумент в пару указателей, и выставить только для чтения контейнера-подобный интерфейс к нему.

Это кажется излишним на первый взгляд, но вы обнаружите, что это очень распространенная функция для использования. Огромный кусок функций, которые принимают std::vector<T> const&, должен принимать значение ro_array_view<T>.

не- ro_array_view немного отличается (его методы все в основном const до сих пор, но он хранит T* не T const*. Я бы назвал это rw_array_view, а затем сделать array_viewusing псевдоним, который условно использует ro_array_view или rw_array_view. Добавить в преобразующий т е р от rw_array_view к ro_array_view, чтобы закончить проект.

у меня есть два разных типа, вместо одного, потому что rw_array_view и ro_array_view имеют различные конструкторы из некоторого контейнера. rw_array_view<T> может быть изготовлен из vector<T,A...>&, а ro_array_view<T> - vector<T, A...>const&. std::array немного хуже, потому что const T является допустимым типом в std::array. И ro_array_view используется в большинстве случаев, причем rw_array_view полезен для случаев, когда мы хотим изменить содержимое без изменения контейнера.

Смежные вопросы