2

I'm writing some intersection code for a Ray tracer. After calculating some intersection logic for a sphere, I want to return an optional to determine if there was an intersection or not. Instead of returning an "invalid" value for distance, I want to use C++'s std::optional class. The only issue is that it seems to always return true for has_value():

std::optional<Intersection> Sphere::ray_intersection(Ray ray)
    // Calculate Intersection Logic
    // ...
    if (distance_to_intersection < 0) {
        return std::nullopt;
    } else {
        return Intersection(ray, distance_to_intersection);
    }
}

After returning, I check using the following code:

if (sphere.ray_intersection(ray).has_value()) {
    return shade(sphere, intersection);
} else {
    return background_color;
}

I know the actual intersection logic works correctly, because when I replace return std::nullopt; with return Intersection(ray, -1); (an invalid distance) and then simply check if the distance is equal to -1 in the previous if check, it behaves as expected.

I've also tried returning a simple {} to no avail.

I'm currently using Microsoft Visual Studio 2022, and I have tried both the C++17 and C++20 compilers, and neither will behave as I'm expecting.

Is there a specific way that std::optional operates that I'm not aware of?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • [Works fine for me](https://onlinegdb.com/qCh3xKVM-), so it is probably a bug in MSVC. That being said, you probably want to pass the found `Intersection` to `shade()`, which means you need to save the `optional` to a variable first, eg: `auto intersection = sphere.ray_intersection(ray); if (intersection.has_value()) { return shade(sphere, intersection.value()); } else { ... }` – Remy Lebeau Apr 22 '22 at 01:51
  • 3
    Try to find and post a [minimal reproducible example(MRE)](https://stackoverflow.com/help/minimal-reproducible-example). An MRE not only helps others to understand your problem, but also usually leads you to find the real problem. – VainMan Apr 22 '22 at 03:30
  • I'm not sure how much more code I could have provided. It covers everything that could be going wrong. I believe it maybe a bug in the MSVC. I attempted to print the contents of `std::nullopt` after returning, and although it would pass the `has_value()` check, all properties would be printed as `NaN`. – Josh McCord Apr 22 '22 at 03:39
  • 4
    @JoshMcCord See how much code [I had to add](https://onlinegdb.com/qCh3xKVM-) to your example just to compile and run it? That is the definition of a [mcve]. In any case, you need to step through the code with a debugger to see exactly what is happening at runtime. The `std::optional` is clearly not being constructed the way you are expecting. – Remy Lebeau Apr 22 '22 at 04:02
  • 2
    Does `Intersection` have a constructor that takes a `std::optional` or `std::nullopt_t`? – Sedenion Apr 22 '22 at 06:05

0 Answers0