Reputation: 667
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
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
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