[ACCEPTED]-static_assert on initializer_list::size()-constexpr

Accepted answer
Score: 36

"Initializer lists" are just horrible kludges.

Don't:

#include <initializer_list>

template<typename T>
void Dont(std::initializer_list<T> list) { // Bad!
    static_assert(list.size() == 3, "Exactly three elements are required.");
}

void Test() { Dont({1,2,3}); }

Do:

template<typename T, std::size_t N>
void Do(const T(&list)[N]) { // Good!
    static_assert(N == 3, "Exactly three elements are required.");
}

void Test() { Do({1,2,3}); }

0

Score: 12

The compiler says that init is the problem, not 8 init.size().

I guess that the constructor 7 could be called from different places with 6 different length initializers.

(To elaborate: You're 5 trying to write a static_assert that depends on the run-time 4 value of the variable init, namely how many elements 3 it has. static_asserts have to be evaluable at the time 2 the function is compiled. Your code is analogous 1 to this trivially invalid example:)

void foo(int i) { static_assert(i == 42, ""); }
int main() { foo(42); }  // but what if there's a caller in another translation unit?
Score: 5

From my discussion with @Evgeny, I realized 4 that this just works (with gcc 4.8 c++11) and may as 3 well do the size check by only accepting 2 a compatible size in the initializer list 1 (in main).

(code link: http://coliru.stacked-crooked.com/a/746e0ae99c518cd6)

#include<array>
template<class T, int Length>
class Point
{
  public:
    Point(std::array<T, Length> init)
    {
//not needed//      static_assert(init.size() == Length, "Wrong number of dimensions");
    }
};

int main()
{
  Point<int, 3> q({1,2,3}); //ok
//  Point<int, 3> q2({1,2,3,4}); //compile error (good!)
  Point<int, 3> q2({1,2}); // ok, compiles, same as {1,2,0}, feature or bug?
  return 0;
}
Score: 2

Use following syntax:

LIVE DEMO

#include <initializer_list>

template<class T, int Length>
class Point
{
    std::initializer_list<T> data;
public:
    constexpr Point(std::initializer_list<T> init)
        : data
        (
            init.size() == Length ?
            init : throw 0
        )
    {}
};

int main()
{
    constexpr Point<int, 3> a{{1,2,3}};
    constexpr Point<int, 2> b{{1,2,3}}; // compile time error
}

Refer following SO.


EDIT: Interesting 3 that works on GCC 4.8.1, but does not work 2 on Clang 3.4. Maybe this is related to constexpr of 1 .size() (afaik, in C++14 it is constexpr).

Score: 0

I haven't really figured out what's going 8 on here.

If I say

const std::initializer_list<double> li = { 1, 2.5, 3.7, 4.3 };
static_assert(li.size() == 4, "fail");

I get a complain that 'li' was 7 not declared 'constexper'.

But if I say

constexpr std::size_t dSize(std::initializer_list<double> di)
{
    return di.size();
}

then

static_assert(dSize({1, 2.5, 3.7, 4.3}) == 4, "failed");   // works

but

static_assert(dSize(li) == 4, "failed");

fails 6 with "error: the value of 'li' is not 5 usable in a constant expression"

This 4 is all with -std=c++11

So, somehow, an initializer 3 list passed into an arg list can be part 2 of a constant expression, but an initializer 1 list just declared as a const variable can't.

More Related questions