36

In C++17, how do you declare and initialize a vector of pairs(or tuples) with an optional element?

    std::vector<std::pair<int, optional<bool> > > vec1 = { {1, true},
                                                           {2, false}, 
                                                           {3, nullptr}};

I have a pair where the second element may be null/optional.

Eugene
  • 10,957
  • 20
  • 69
  • 97
  • 1
    `std::piecewise_construct` can also provide interesting alternatives. – Marc Glisse Mar 11 '20 at 20:49
  • 4
    Does this answer your question? [How to assign "nothing" to std::optional?](https://stackoverflow.com/questions/47441623/how-to-assign-nothing-to-stdoptionalt) – Julien Lopez Mar 11 '20 at 21:22
  • @JulienLopez That's talking about assignment. – L. F. Mar 12 '20 at 12:34
  • @L.F. It's the same question when you remove the irrelevant context: how do you create an empty optional? – Julien Lopez Mar 12 '20 at 13:54
  • 1
    @JulienLopez In C++, initialization and assignment are very different in general. Just because the two questions happen to have overlapping solutions doesn't mean that they are the same. In particular, note that you don't want to use `reset` here. – L. F. Mar 12 '20 at 13:58

2 Answers2

54

You are looking for std::nullopt instead of nullptr.

std::vector<std::pair<int, std::optional<bool> > > vec1 =
  { {1, true}, {2,false}, {3,std::nullopt} };
Erlkoenig
  • 2,664
  • 1
  • 9
  • 18
bitmask
  • 32,434
  • 14
  • 99
  • 159
  • 3
    (Coming here from the hot network questions link) Does C++ code always spam `std::` like this? Why not just `using std::vector` and friends, so you could just write `vector>`? Reads way more sanely – Alexander Mar 11 '20 at 19:55
  • 19
    @Alexander-ReinstateMonica "Reads way more sanely" is subjective. The flip side of the readability argument is something like this: I don't want to have to go all the way back to the top of the file to figure out _which particular_ `vector`, `pair`, `optional`, etc. I'm using in this line. Including the namespace inline tells me unambiguously where that function comes from and what it does; the line is self-contained. This is especially true for bigger projects (since it avoids namespace conflicts entirely), but also useful for concise code examples. – probably_someone Mar 11 '20 at 20:31
  • 1
    @probably_someone How frequently do people use `vector`/`pair`/`optional` that aren't `std::`? – Alexander Mar 11 '20 at 22:32
  • 2
    @Alexander-ReinstateMonica More often than you might think. Here's just one example: https://stackoverflow.com/questions/24217071/c-class-name-conflict – probably_someone Mar 11 '20 at 22:34
  • 2
    @Alexander-ReinstateMonica Here's another one, that doesn't involve C at all: https://stackoverflow.com/questions/13292786/name-conflict-with-standard-library – probably_someone Mar 11 '20 at 22:36
  • 1
    @probably_someone Seems like an exceptional case. I wouldn't build rules around catering to exceptional cases. BTW I'm aware of the guidance to not `using namespace std;`. It's similar to the Java advice to not use wildcard includes like `include java.util.*;`. But no one suggests to always use fully qualified types like `java.util.function.Function`, in the off chance someone else decided to name their type `Function`. Just include it and use the short version, and only use the qualified syntax in the off cases that collisions occur. Seems pretty straight forward – Alexander Mar 11 '20 at 23:20
  • 3
    @Alexander-ReinstateMonica That logic is fine if you have full supervision and control over any code that uses the code you just wrote (because then you know precisely when an "off case in which collisions occur" happens). But if you're doing something like, for example, developing a library or an API that's intended for use by a bunch of other developers, you can't supervise every single usage to figure out if/when such a collision occurs. It's usually better in that (relatively common) case to pre-empt collisions, rather than fix them only after someone complains that your product is broken. – probably_someone Mar 11 '20 at 23:29
  • 3
    @Alexander-ReinstateMonica Which of the following do you immediately realize is a top-level name from `std`? `arg`, `count`, `find`, `size` – L. F. Mar 12 '20 at 02:21
  • 4
    @Alexander-ReinstateMonica, to me, `std::` is totally unobstrusive. It would be different if the name of the namespace was much longer. – Carsten S Mar 12 '20 at 10:27
  • @L.F. You could just use it in places where it's near-obvious, like vector. Moderation is possible. – Alexander Mar 12 '20 at 12:03
  • @Alexander-ReinstateMonica [`vector`](https://en.wikipedia.org/wiki/Vector) has the same problem: [`math::vector`](https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics))? [`simd::vector`](https://en.wikipedia.org/wiki/SIMD)? [`epidemiology::vector`](https://en.wikipedia.org/wiki/Vector_(epidemiology))? – L. F. Mar 12 '20 at 12:19
  • @L.F. I think you're being disingenuous. Come on, when you see `vector` in a C++ program, how often do you think "ah yes, must have to do with epidemiology"? – Alexander Mar 12 '20 at 12:33
  • @Alexander-ReinstateMonica Yeah, that epidemiology is kinda intended to be a "funny" example. The point is that `std::vector` makes it clear what vector we're referring too. Moreover, qualified names (e.g., `std::vector`) and unqualified names (e.g., `vector`) are treated differently in C++ sometimes. Qualifying isn't necessary in small scopes, but for large programs, it boosts readability. – L. F. Mar 12 '20 at 12:39
  • @L.F. Ok, fair enough. I think I'm missing some piece of understanding with how C++ handles this. Name ambiguity is a problem in pretty much every programming language with identifiers (which is all of them?). Java, for example, has the exact same issue. Yet nobody writes `java.util.ArrayList` except for the one-time import at the top of the file. Sure, if there's some other `ArrayList` implementation, that would could pose an issue. But we don't have to lose our minds; it's a trivial problem. Just fully qualify it when you need to. – Alexander Mar 12 '20 at 12:45
25

Or simple use default construction:

std::vector<std::pair<int, std::optional<bool>>> vec1 {
    {1, true}, {2,false}, {3,{}}
};
Marek R
  • 32,568
  • 6
  • 55
  • 140