What is happening in this code? Is so confusing.
#include <utility>
struct check
{
template <typename T>
auto foo() -> decltype(std::declval<T>().value, void())
{
static_assert(T{}.value == 10, "Incorrect value");
}
} var;
int main()
{
struct apple
{
int value{10};
};
var.foo<apple>();
}
Specifically the part where it has ->
and everything after that.
Let's go through bit by bit.
auto foo() -> decltype(std::declval<T>().value, void())
This is a trailing return type. It's allowed to use parameters, but here that isn't necessary. I'd guess it's written like that to be clearer. decltype
finds the type of the expression inside, but that expression is not actually evaluated. std::declval
is used for creating an instance of the type passed to it. The comma operator is used here to make the overall return type void
, since the comma operator evaluates the left side, throws it away, evaluates the right side, and returns that.
The first part creates a sort of SFINAE (though I've never seen it used like this). For example, if you had an overload of foo
that did the same with value2
instead of value
, there would be no ambiguity of which to call. See here for what I mean. Compare it to this one, which just has a return type of void
and causes errors.
static_assert(T{}.value == 10, "Incorrect value");
This line makes sure a value-initialized instance of T
has its value
member have a value of 10. If it doesn't, a compiler error with that text is generated.
} var;
This is just a global object of that class to use.
struct apple
{
int value{10};
};
This is a sample class to test it with. It has a value
member and that member is 10 in a value-initialized instance (default-initialized as well).
var.foo<apple>();
This just calls the function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With