Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: when built with /std:c++latest or future /std:c++23, support std::expected<> for wil::reg::try_* #452

Open
fredemmott opened this issue Jul 23, 2024 · 3 comments
Labels
feature-request New feature or request

Comments

@fredemmott
Copy link

Something like std::expected<std::wstring, HRESULT> = wil::reg::try_get(...) would be a very handy API :)

@dunhor dunhor added the feature-request New feature or request label Jul 25, 2024
@citelao
Copy link
Contributor

citelao commented Aug 23, 2024

Ooh, that's super cool! I didn't know about that API. @keith-horton, you might like this---it'd let us have safer nothrow variants!

Something like this, right?

auto value = wil::reg::try_get_dword(...);
if (value.has_value())
{
  std::cout << "value: " << *value << '\n';
}
else if (value.error() == E_FILE_NOT_FOUND)
{
  // ...
}
// ...

Edit: for clarity, I'm not sure I have the bandwidth to add this, and I'm not sure Keith does either. But I think it's a good suggestion :)

@computerquip-work
Copy link

computerquip-work commented Aug 30, 2024

At some point, I used this with Boost Outcome's result type, similar to:

template <typename T>
using hr_result = result<T, HRESULT>

// ...

class thing
{
private:
    thing() nothrow;

public:
    thing(const thing &) = delete;
    thing(thing &&) = default;
    thing &operator(const thing &) = delete;
    thing &operator(thing &&) = default;

    static hr_result<thing> create();
}

This pattern allows me to avoid exceptions without the need to have out parameters for results. Without a result type like this, it actually wouldn't be possible to make the default constructor private and two-phase construction ends up being a requirement or an HRESULT out parameter is required.

Then I would have macros specifically designed to check the errors, log them if they failed, and return on failure. Back when I did this, I did it with clang-cl so it ended up looking pretty dang decent:

hr_result<DWORD> do_something()
{    
    return TRYX(do_a_thing()) + TRYX(do_another_thing());
}

which ends up pretty close to how Rust looks with ? syntax, just more verbose.

The MSVC alternative would be:

hr_result<DWORD> do_something()
{    
    DWORD a{};
    DWORD b{};

    TRY(a, do_a_thing());
    TRY(b, do_another_thing());

    return a + b;
}

or

hr_result<DWORD> do_something()
{
    TRY(DWORD a, do_a_thing());
    TRY(DWORD b, do_another_thing());

    return a + b;
}

In future projects, I stopped doing this because the logging of errors on the Windows platform is convoluted to say the least and I needed boilerplate to handle that every time, boilerplate that WIL already handles. I also had to recreate/drag the various check macros around specifically meant for Windows result types that had to wrap around boost outcomes result macros. I really like this pattern but the setup was very inconvenient, especially for small codebases.

Just some food for thought.

@citelao
Copy link
Contributor

citelao commented Sep 2, 2024

Is this something that could be done generically across all of WIL at once? Eg a helper of some sort.

Not sure how you could automatically “forward” outparams though…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants