3

I have std::variant where all classes are derived from the same base. I want to cast variant to base.

return std::visit( []( const Base& b ) { return b; }, v );

This compiles but gives warning C4172: returning address of local variable or temporary

Is there a way to visit std::variant in place, without making local or temporary copies?

Or if it’s impossible, how can I cast the value to void* so I can use static_cast ?

Update: I thought the example should be obvious, but it's not, here's the complete repro:

#include <variant>

struct Base {};
struct A : Base {};
struct B : Base {};

const Base& cast( const std::variant<A, B>& v )
{
    return std::visit( []( Base const& b ) { return b; }, v );
}

int main()
{
    std::variant<A, B> v{ A{} };
    const auto& b = cast( v );
}
Soonts
  • 20,079
  • 9
  • 57
  • 130
  • @Justin Because you're ignoring the return value. https://godbolt.org/z/ArZZzF – Soonts Dec 20 '18 at 18:06
  • 1
    _"I thought the example should be obvious"_ yet the return type of `cast` is a key part of the problem and (in concert with the return type of your visitor) is what triggers the warning. Please get into the habit of _always_ providing a [MCVE] because 9 times out of 10 your assumptions on what is irrelevant will be wrong. After all, you didn't know what caused the problem, right? :) This uncertainty is the reason for the MCVE rule. – Lightness Races in Orbit Dec 20 '18 at 18:46
  • @LightnessRacesinOrbit “you didn't know what caused the problem” I did know where the problem is, the compiler told me that. The solution, too, only applies to the original code I’ve posted, making the complete repro irrelevant. – Soonts Dec 20 '18 at 19:26
  • @LightnessRacesinOrbit The initial comment by Justin who said “unable to reproduce” and linked to https://godbolt.org/z/XZqLAs was caused by him neglecting the “return” statement in my code, not by a lack of context. – Soonts Dec 20 '18 at 19:28
  • @Soonts No, it was absolutely caused by a lack of context. If you change `cast` to return by value, there is no error, no problem whatsoever. – Justin Dec 21 '18 at 17:14

1 Answers1

5

Lambdas have return type deduction, but they deduce the return type by value. It's as if they are a function returning auto, not decltype(auto). If you want to return by reference, you need to specify the return type.

Thus, [](const Base& b) { return b; } returns by value, copying b. Explicitly specify the return type to force it to return by reference:

const Base& cast( const std::variant<A, B>& v )
{
    return std::visit( []( Base const& b ) -> Base const& { return b; }, v );
}
Justin
  • 24,288
  • 12
  • 92
  • 142
  • I mean, `b` _is_ a `const Base`. That's how references work. They're not fancy pointers, they are just ways to produce alternative names for existing objects. That is, `b` is the name of the object, not of "the reference". So in reality this is a little more fundamental than just the rules of the lambda. Anyway, you're right though. – Lightness Races in Orbit Dec 20 '18 at 18:48