7

I'm interested to know why the second static_assert in my code below doesn't work. It seems like even though the array c is a reference to a, the size of the array is embedded in the type, so it should be available at compile time.

#include <array>

int main()
{
    std::array<int,2> a = {1,2};
    std::array<int,2> b = {2,3};
    std::array<int,2>& c = a;

    static_assert(a.size() == b.size(), "a.size==b.size"); // ok size of array is compile time constant
    static_assert(c.size() == a.size(), "c.size==a.size"); // compiler error "static_assert expression is not an integral constant expression"
}
3
  • does this answer your question: stackoverflow.com/questions/28614591/… Commented Aug 9, 2020 at 21:43
  • 3
    because a is not constant expression Commented Aug 9, 2020 at 21:43
  • I'm now interested why std::declval<decltype(c)>().size() works with MSVC, but not with clang nor gcc. Commented Aug 10, 2020 at 9:23

2 Answers 2

8

the size of the array is embedded in the type, so it should be available at compile time.

This is true. But regardless, c is not a constant expression and therefore expression that contains it as a subexpression cannot be a constant expression - except certain operators that interact only with the type of the operand such as sizeof.

You can get the size for example using:

static_assert(
    std::tuple_size<
        std::remove_reference_t<decltype(c)>
    >::value == a.size(),
    "c.size==a.size"
);

Unfortunately, it is not very pretty.

Sign up to request clarification or add additional context in comments.

1 Comment

could probably wrap it into a derived template.. Tuple_size is nothing more than integral_constant which uses sizeof(), so straight-forward sizeof() idiom works too, if tuple_size isn't included into implementation (it sometimes overlooked).
3

Note, that if you move all declaration out of main function, code would compile. Why? Because a is automatic variable, so it's not really a compile time object and reference is not elided here, therefore neither a nor cor c.size() are constexpr. For global variables location of a can be determined at compile time.

IF you try bind them within function like this:

constexpr std::array<int,2> a = {1,2};
std::array<int,2> b = {2,3};
constexpr const std::array<int,2>& c = a;

You'll get error that a is not a constant expression. Variant which still may compile:

#include <array>

std::array<int,2> a = {1,2};
std::array<int,2> b = {2,3};

int main()
{
    std::array<int,2>& c = a;

    static_assert(a.size() == b.size(), "a.size==b.size"); 
    static_assert(c.size() == a.size(), "c.size==a.size"); 
}

3 Comments

This behaviour just goes to show how ridiculous C++ can be.
@PaulSanders Russel's paradox sound ridiculous too, but it is logical. We had created a run-time alias for "something" which was created run-time, but we ask question about properties known in compile time, using function sizeof() call to which is sensitive to nature of object it is invoked with. The is no logical way to formulate rules how compiler have to divine that we ask about something it can deduce.
size(), not sizeof(), that's a typo

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.