1

I'm trying to get my class to support initializer lists.

#include <array>
#include <initializer_list>

template <class value_type, size_t Size>
class Queue {
    std::array<value_type,Size> m_data;
    size_t m_last_write;

public:
    Queue(std::initializer_list<value_type> list) :
        m_last_write(0)
    {
        static_assert( list.size() <= Size, "Initializer list length is longer than Queue has been configured for");

        for (auto& datum : list)
            push(datum);
    }

    void push(const value_type& val)
    {
        if (++m_last_write >= Size);
            m_last_write -= Size;

        m_data[ next_i ] = val;
    }
};

Everything works well here except for the static_assert. Where I get:

error: non-constant condition for static assertion

error: ‘list’ is not a constant expression

This sounds like the same issue that this guy ran into.

One of the proposed solutions there suggests this as the answer:

template<size_t N>
Queue(const value_type(&list)[N] ) :
    m_last_write(0)
{
    static_assert( N <= Size , "Too big!" );

    for (auto& datum: list)
        push(datum);
}

However, when I use this initializer list:

Queue<int,10> r = {66,55,44};

I get this error:

error: could not convert ‘{66, 55, 44}’ from < brace-enclosed initializer list> to Queue< int, 10ul>

Community
  • 1
  • 1
Stewart
  • 4,356
  • 2
  • 27
  • 59
  • 3
    You cannot use `static_assert` for something that will be known at runtime only. How about throwing an exception instead? – Yksisarvinen Oct 08 '18 at 08:37
  • The last example I give (which avoids std::initializer_list) should be deduced at compile-time. – Stewart Oct 08 '18 at 08:39
  • argument are not `constexpr`, and we cannot know size from the *type* `std::initializer_list`. – Jarod42 Oct 08 '18 at 08:42
  • Perhaps I'm confused between `brace-enclosed initializer list` and `std::initializer_list`. I understand that `std::initializer_list::size` isn't `constexpr`, so perhaps I'm trying to use `brace-enclosed initializer list` as if it were a `std::initializer_list` even though they are entirely independent. – Stewart Oct 08 '18 at 08:44
  • Note that `std::initializer_list::size` is `constexpr` since c++14. – Zereges Oct 08 '18 at 08:48

1 Answers1

1

The problem of solution you posted is that in the list initialization, i.e. Queue<int,10> r = {66,55,44};, the constructors of Queue are considered in overload resolution to match the three arguments 66, 55, 44, then the match fails.

You can add two more braces as the workaround, then the argument {66,55,44} will be used as one argument to match the constructors' parameter; then it matches the one takes an array and works as expected.

Queue<int,10> r = {{66,55,44}};
songyuanyao
  • 169,198
  • 16
  • 310
  • 405