C++11 Vector class initialization

This is a discussion on C++11 Vector class initialization within the C++ Programming forums, part of the General Programming Boards category; Hi everybody, I'm working on a vector class - the mathematical kind - for C++11. I'm trying to find a ...

  1. #1
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262

    C++11 Vector class initialization

    Hi everybody,

    I'm working on a vector class - the mathematical kind - for C++11. I'm trying to find a decent way for initialization, such as:
    Code:
    Vector<3> v{ 0, 1, 2 };
    My first idea was to use an initializer list. However, as size() is not a constexpr (Why? I've looked around and it seems possible to implement, does it cause any additional issues?), the number of arguments isn't verified at compile time.

    So I looked into the std::array class. It seems to simply make the array a public member of the class (actually, struct), such that it can be initialized similarly to the above code, except that it changes the assignment syntax to:
    Code:
    std::array<int, 3> v{{ 0, 1, 2 }};
    Except for assignment, that is. This works fine, but it becomes messy for multi-dimensional arrays (or, matrices), and I don't like the syntax.

    So I wrote up a quick test, and it looks like this:
    Code:
    template<typename ArrayType, size_t ELEMENTS>
    class ArrayAssign {
    public:
        template<typename... Args>
        static inline void assign(ArrayType array, Args... args)
        {
            static_assert(sizeof...(args) == ELEMENTS,
                          "Invalid number of parameters.");
            
            _assign(array, 0, args...);
        }
        
    private:
        template<typename... Args>
        static inline void _assign(ArrayType array, size_t i,
                                   const decltype(ArrayType()[0])& v, Args... args)
        {
            array[i] = v;
            _assign(array, i+1, args...);
        }
        
        
        static inline void _assign(ArrayType array, size_t i,
                                   const decltype(ArrayType()[0])& v)
        {
            array[i] = v;
        }
    };
    Then, the vector class has a constructor:
    Code:
    template<size_t N, typename Type = double>
    class Vector {
      public:
            template<typename... Args>
            Vector(Args... args)
            {
                ArrayAssign<Type*, N>::assign(v, args...);
            }
    ...
    This actually works as I expected. The first code snippet works, and the initialization syntax looks a lot clearer to me.
    I haven't checked if I can get it to work for matrices as well though, there are some issues as it is now (I'll look into it).

    My questions:
    1. Are there any side effects that I'm missing, causing this method to be inferior to the method std::array uses?
    2. What *are* the issues with std::initializer_list::size() being constexpr?


    Thanks in advance
    Last edited by EVOEx; 10-13-2012 at 04:11 PM.

  2. #2
    Registered User
    Join Date
    Aug 2010
    Location
    Poland
    Posts
    681
    `std::initializer_list` cannot be a `constexpr` class because it uses pointers to store its data and uses pointer arithmetic to return its size.

    While pointers can certainly be used in constant expressions, most of the time they are acquired at run-time, e.g. via the new operator or std::malloc. Taking address of a variable on the stack is also a run-time operation (have a look at your initialisers).

    The only case, which I know of, when you can use pointers in your constant world are pointers to symbols with external linkage, since their address is known at compile-time. Of course, the nullptr constant fall into this category too.
    Last edited by kmdv; 10-15-2012 at 08:36 AM.
    I never put signature, but I decided to make an exception.

  3. #3
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    4,171
    Are there any side effects that I'm missing, causing this method to be inferior to the method std::array uses?
    O_o

    I only looked at this for like a second, but I believe you break static initialization (the constructor must be called) which the public array gets you.

    I can look at it more, but that's probably the biggest "trade".

    [Edit]
    By the by, `ArrayAssign<Type*, N>::assign' should really be a named function (wrapping interface).
    [/Edit]

    [Edit]
    Also, even though the standard only claims leading underscore followed by an underscore or uppercase letter you should avoid the leading underscore always.

    It is as simple as this: some vendors misunderstood what exactly the standard says and so used macros of the form "_$" where "$" is a lowercase letter.
    [/Edit]

    What *are* the issues with std::initializer_list::size() being constexpr?
    You can't calculate the distance using iterators or pointer differencing because they are not compile-time constructs; you'd have to have a construct that works at compile-time.

    Basically, you'd have to have `std::initializer_list<type, element_count>'.

    Soma

  4. #4
    Registered User
    Join Date
    Oct 2008
    Posts
    1,262
    Thanks for your replies!

    Actually, I've found a big issue with my method: the fact that it doesn't seem to be able to derive the type of the constructor's arguments. For example, for a matrix, if I have something like this:
    Code:
    template<typename... Args>
    Matrix(Args... args)
    {
        ArrayAssign<Vector<COLS>*, ROWS>::assign(m, args...);
    }
    Now when calling the matrix constructor like this won't work:
    Code:
    Matrix<2, 2> m{
        { 1.0, 0.0 },
        { 0.0, 1.0 }
    }
    As the compiler doesn't seem to know the arguments to the Matrix constructors are themselves vectors, and should be interpreted as such (not too strange when you think of it). This following works, but defeats the entire purpose of why I even considered it:

    Code:
    Matrix<2, 2> m{
        Vector<2>{ 1.0, 0.0 },
        Vector<2>{ 0.0, 1.0 }
    }

    So scratch that - I'm back to the array format with double braces.


    Quote Originally Posted by phantomotap
    Basically, you'd have to have `std::initializer_list<type, element_count>'.
    Hmmm good point... I'm still considering which I like more though, but it's definitely a strong argument towards the current version.


    Thanks guys!
    Last edited by EVOEx; 10-15-2012 at 10:26 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bool initialization in class
    By FlyingIsFun1217 in forum C++ Programming
    Replies: 10
    Last Post: 08-05-2008, 02:33 AM
  2. Initialization of class members
    By misterowakka in forum C++ Programming
    Replies: 3
    Last Post: 02-02-2008, 12:35 PM
  3. class initialization and the = operator
    By krygen in forum C++ Programming
    Replies: 3
    Last Post: 01-26-2005, 11:44 PM
  4. Base class initialization
    By VirtualAce in forum C++ Programming
    Replies: 4
    Last Post: 01-11-2004, 03:52 AM
  5. Class constructor with initialization
    By WebSnozz in forum C++ Programming
    Replies: 1
    Last Post: 11-20-2001, 04:31 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21