user1819047
user1819047

Reputation: 667

c++ why this static_assert works:

I have the following questions regarding the constexpr, I kinda understand that one cannot declare a std::shared_ptr<T> to be const, but why does the first static_assert() works?

Also, how does the second static_assert() work? I wanted to have an array of std::variants, which are consts, and wanted to have compile-time type-checking to enforce the type; however, it seems that if a std::shared_ptr is one of the variant type, then it cannot be declared constexpr; but if I declare the container as std::tuple, even without the constexpr annotation, (I) seemed to work;

typedef std::shared_ptr<int> intp;

const auto defaults = std::make_tuple(std::make_pair(1, true),
                                  std::make_pair(2, 3),
                                  std::make_pair(3, intp(nullptr)));


typedef std::variant<int, bool> MyVar;
constexpr MyVar var1 = 3;

// constexpr intp x = nullptr; (I)
//typedef std::variant<int, bool, intp> MyVar2; This doesn't work
//constexpr MyVar2 var2 = 3;

int main()
{
    // Q1): Why the following works, but (I) does not.
    static_assert(std::is_same<decltype(std::get<2>(defaults).second), intp>::value);
    // Q2): Why this works: is there a better way to say something like
    //      static_assert(actual_type(var1) == int);
    static_assert(std::get<int>(var1) == 3);
    //static_assert(x == nullptr);  This does not work 
}

Upvotes: 2

Views: 1044

Answers (2)

AndyG
AndyG

Reputation: 41220

// Q1): Why the following works, but (I) does not.
static_assert(std::is_same<decltype(std::get<2>(defaults).second), intp>::value);

Here's the magic: in C++ some expressions are considered unevaluated. decltype(...) is one of them (refer to [dcl.type.simple])

What does it mean for decltype(...) to be unevaluated?

In this context, the common purpose of writing the expression is merely to refer to its type.

Think of it more like a fancy typedef. Nothing can ever actually be created from within this context. You can do some interesting things with it, like use incomplete types.


The reason why

typedef std::shared_ptr<int> intp;
constexpr intp x = nullptr; 

doesn't work should now become obvious: this expression is evaluated, and since we know that we cannot create a constexpr shared_ptr, compilation fails.


// Q2): Why this works: is there a better way to say something like
// static_assert(actual_type(var1) == int);?
static_assert(std::get<int>(var1) == 3);

This works because a std::variant has a constexpr constructor, and you are constructing it with a compile-time integer value of 3 which constructs the int field of the variant.

Next, std::get on a variant is also marked constexpr, and since the variant is constructedd as constexpr, we can obtain the value 3 at compile-time.

Upvotes: 0

max66
max66

Reputation: 66230

I kinda understand that one cannot declare a shared_ptr to be const, but why does the first static_assert works?

Because

static_assert(std::is_same<decltype(std::get<2>(defaults).second), intp>::value);

doesn't create a compile-time stared_ptr; only check if the type of std::get<2>(defaults).second is a intp.

This information is known compile time also if the values are available only run time.

Also, how does the second static_assert work? I wanted to have an array of std::variants, which are consts, and wanted to have compile-time type-checking to enforce the type; however, it seems that if a shared_ptr is one of the variant type, then it cannot be declared constexpr; but if I declare the container as std::tuple, even without the constexpr annotation, (I) seemed to work;

Not sure what you mean.

If for "second static_assert work" do you mean

static_assert(std::get<int>(var1) == 3);

it's because var1 is constexpr and std::get() (for std::variant) is constexpr; so std::get<int>(var1) it's a value that can be used, compile time, in a static_assert() With

Upvotes: 3

Related Questions