3

We currently use C++11. std::optional is missing from C++11 - it has been introduced in C++17. Luckily, I found an implementation which has the same interface as std::optional and works in C++11 (https://github.com/TartanLlama/optional)

This defines optional in namespace tl. So, I can use it like so:

#include "optional.hpp"

tl::optional<int> to_int(string str) {
    if (...) { return atoi(str); } 
    else     { return tl::nullopt; }
} 

However, I am looking for a way to call this as if std::optional was available:

#include "optional.hpp"

std::optional<int> to_int(string str) {
    if (...) { return atoi(str); } 
    else     { return std::nullopt; }
} 

This way, when we switch to C++17, I will not have to replace each tl::optional with std::optional. I will only have to replace the contents of the "optional.hpp" header with:

// optional.hpp 
// ------------
#include <optional.hpp>

Today, this header is implemented as:

// optional.hpp 
// ------------
#include "tl/optional.hpp"   // include the official header, when C++17 is available

How can I create some sort of an alias in this header, so that when I call std::optional it will actually refer to the tl::optional ?

  • I cannot touch the original code of tl/optional.hpp.
  • I would prefer not to use a macro
Grim Fandango
  • 2,296
  • 1
  • 19
  • 27
  • like this: https://stackoverflow.com/a/2795024/1563833 – Wyck Oct 27 '20 at 17:05
  • Use [Boost optional](https://www.boost.org/doc/libs/1_74_0/libs/optional/doc/html/index.html) instead? Generally adding anything to the `std` namespace (except in a few and very limited situations) leads to *undefined behavior*. – Some programmer dude Oct 27 '20 at 17:06
  • 3
    `namespace grim { using tl::optional; }` Use `grim::optional` everywhere. Change the using in Grim's one header to `using std::optional;` when you've moved to C++17, assuming they are API surface compatible. Otherwise if not drop-in compatible, you'll also need to cleanup the callsites too. – Eljay Oct 27 '20 at 17:10
  • 3
    [Extending the namespace std](https://en.cppreference.com/w/cpp/language/extending_std) says: _"It is undefined behavior to add declarations or definitions to namespace std or to any namespace nested within std"_ – Wyck Oct 27 '20 at 17:12
  • @Wyck, if C++11 is not aware of the existence of `std::optional`, it realistically wouldn't hurt if introduced it. – Grim Fandango Oct 27 '20 at 17:14
  • Replacing "tl::optional" with "std::optional" is one global search-and-replace operation (or one `sed` command), and it will take seconds. Don't waste your time. – molbdnilo Oct 27 '20 at 17:16
  • 1
    If they say it is undefined behaviour, it is. You cannot define the behaviour with any definition of your own. undefined behaviour is exactly that. Which could include destroying my house, so please don't. – Wyck Oct 27 '20 at 17:16
  • @GrimFandango that's groovy right up until you find there's already something named `optional` buried in `std` and not exposed. – user4581301 Oct 27 '20 at 17:18
  • @Eljay, my biggest issue is with introducing `tl::nullopt` inside the `std` namespace. `tl::nullopt` is a `constexpr` function that returns a `tl::nullopt_t`. I've tried writing: `namespace std { using nullopt = tl::nullopt; }` but I get an error: `"nullopt" is not a member of 'std'` – Grim Fandango Oct 27 '20 at 17:19
  • this std::optional reading about UB is entirely std::optional https://softwareengineering.stackexchange.com/questions/99692/philosophy-behind-undefined-behavior – Wyck Oct 27 '20 at 17:19
  • @Wyck, I guess you're right -- Eljay's proposal seems the most promising one. – Grim Fandango Oct 27 '20 at 17:27

1 Answers1

5

How to introduce a struct in the std namespace

By writing a proposal to the standards committee. But in this case the class is already adopted, so what you need to do to get the class is start using the new version of the standard.

How can I create some sort of an alias in this header, so that when I call std::optional it will actually refer to the tl::optional ?

As not-the-standard-library-implementer, you are not allowed to introduce classes into the std namespace.

What you can have instead, is an alias in your own namespace:

namespace my_very_own {
    using tl::optional; // change to std::optional when possible
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • I have issues moving the tl::nullopt inside this namespace. `namespace my_very_own { using tl::nullopt' }` does not seem to work -- `nullopt` is not a typename – Grim Fandango Oct 27 '20 at 17:26
  • @GrimFandango I could not reproduce: https://godbolt.org/z/4cfYxT Create a [mcve] – eerorika Oct 27 '20 at 17:41
  • for some reason, I wrote: `namespace my_very_own { using optional = tl::optional; }` and it worked. But this one, didn't: `namespace my_very_own { using nullopt = tl::nullopt; }` Your answer is fine – Grim Fandango Oct 27 '20 at 17:58
  • @GrimFandango My initial answer was closer to that since I didn't remember this shorter syntax. That works with types only; not variables. The plain `using` does work with variables too. – eerorika Oct 27 '20 at 18:11
  • 1
    @GrimFandango `using X = Y;` only works with types and namespaces. `t1::optional` is a type, but `t1::nullopt` is neither, it is actually a *constant* of type `t1::nullopt_t`. You can use `namespace my_very_own { using t1::nullopt; }` instead, it works fine: [Demo](https://ideone.com/nkVrNH) – Remy Lebeau Oct 27 '20 at 18:31