2013-05-02 14 views
9

Mam struct, który posiada tablicę i chciałbym przekazać listę inicjatora do konstruktora struct, aby przekazać ją do tablicy. Aby zilustrować, próbowałem:Jaki jest poprawny sposób inicjowania tablicy elementów z listą inicjalizatora?

#include <initializer_list> 

struct Vector 
{ 
    float v[3]; 

    Vector(std::initializer_list<float> values) : v{values} {} 
}; 

int main() 
{ 
    Vector v = {1, 2, 3}; 
} 

Which resulted in the error:

error: cannot convert ‘std::initializer_list<float>’ to ‘float’ in initialization

I tried using parentheses instead of braces dla v ale dał błąd:

error: incompatible types in assignment of ‘std::initializer_list<float>’ to ‘float [3]’

Moją główną motywacją dla próbuje to zrobić, aby uniknąć po ostrzeżeniu, że clang generuje:

template <int N> 
struct Vector 
{ 
    float v[N]; 
}; 

template <> 
struct Vector<2> 
{ 
    float x, y; 
}; 

int main() 
{ 
    Vector<2> v2 = {1.0f, 2.0f};   // Yay, works 
    Vector<3> v3 = {1.0f, 2.0f, 3.0f}; // Results in warning in clang++ 
    Vector<3> u3 = {{1.0f, 2.0f, 3.0f}}; // Must use two braces to avoid warning 
    // If I could make Vector<N> take an initializer list in its constructor, I 
    // could forward that on to the member array and avoid using the double braces 
} 

warning: suggest braces around initialization of subobject

Moje pytanie brzmi: Jak zainicjować element członkowski z listy inicjalizatora? (Tj Jak mogę zrobić pierwszy pracę kodu? A może to nie jest możliwe?

+0

W przypadku kruszywa nie potrzebowałbyś nawet ctor. Zwróć uwagę, że rozmiar 'initializer_list' jest zmienny. Istnieje również różnica między inicjowaniem z 'initializer-list' i _list-initialization_ (która jest konstrukcją językową i może prowadzić do wywoływania ctor używając listy inicjalizującej). – dyp

+0

Naprawdę nie możesz tego zrobić, ale czy zamiast tego możesz użyć 'std :: array'? – juanchopanza

+0

Mógłby użyć std :: array, ale przeczytałem to jako pytanie o język, a nie standardową bibliotekę. I, z całym szacunkiem dla każdego, powiedzenie komuś, by przeczytała standardową bibliotekę, przypomina opowiadanie maluchowi naukę języka angielskiego, czytając Szekspira. Zatem std :: array nie jest dobrą odpowiedzią. –

Odpowiedz

9

Jeśli klasa jest aggregate, można użyć składni

template < std::size_t len > 
struct Vector 
{ 
    float elems[len]; 
}; 

Vector<3> v = {1.0f, 2.0f, 3.0f}; 

Uwaga: jest to możliwe z powodu uelastycznienia.Nie trzeba jednak v = {{1,2,3}};, choć jest to również możliwe. Clang wydaje to ostrzeżenie, ponieważ wyraźniejsza i mniej podatna na błędy składnia jest z podwójnymi nawiasami klamrowymi (jeden do inicjowania v i jeden do zainicjowania subgrupy elems).

Jeśli klasa nie jest agregatem, można użyć zmiennej liczbie argumentów szablony:

#include <array> 
#include <cstddef> 

template < std::size_t len > 
struct Vector 
{ 
    std::array < float, len > m; // also works with raw array `float m[len];` 

    template < typename... TT > 
    Vector(TT... pp) : m{{pp...}} 
    {} 

    // better, using perfect forwarding: 
    // template < typename... TT > 
    // Vector(TT&&... pp) : m{{std::forward<TT>(pp)...}} 
    // {} 
}; 

Vector<3> a = {1.0f, 2.0f, 3.0f}; 
2

spróbuje użyć std::copy.

Vector(std::initializer_list<float> values) 
{ 
    std::copy(values.begin(), values.end(), v); 
} 
+0

Co się stanie, jeśli lista będzie większa niż pojemność v? –

12

Plain C tablice stylu nie są przypisane. Jeśli przełączysz się na używanie std::array, inicjalizacja stanie się banalna.

#include <array> 

struct Vector 
{ 
    std::array<float, 3> v; 

    Vector(std::array<float, 3> const& values) 
    : v(values) 
    {} 
}; 

int main() 
{ 
    Vector v{{1, 2, 3}}; 
} 
+0

+1 za polecenie 'std :: array'. Pozwala na znacznie lepszą składnię do inicjalizacji. –

0

Aby zainicjować element niestatyczny w tablicy, użyj składni zagregowanej. Oznacza to, że bezpośrednio wypełnia się listę z elementami N, gdzie N jest liczbą elementów w tablicy. Możesz użyć mniej niż N, jeśli typem elementu jest Domyślny-Zbudowany; brakujące elementy zostaną zainicjowane wartością.

Brak konwersji z std::initializer_list do tablicy. Nawet jeśli używasz typu źródłowego, który mógłby zostać przekonwertowany na odwołanie do tablicy (nigdy wartość), nie można wykorzystać konwersji w inicjatorze członkostwa, ponieważ tablice nie są przypisywalne. W takich przypadkach musisz użyć czegoś takiego jak std::copy w ciele konstruktora.

Uwaga dla tablic wielowymiarowych, ponieważ tablice nie są przypisywalne, do tworzenia pod-tablic używa się tylko list usztywnionych. Istnieje także opcja elewacji; za pomocą płaskiej listy pozycji std::remove_all_extents<TheArrayType>::type, a kompilator wykona. (Kiedy wewnętrzny typ nie będący tablicą jest wbudowanym typem znaku, czasami można użyć cytowanego ciągu jako następnego do najdalszego inicjalizatora wielowymiarowej tablicy.)

Powiązane problemy