Instead of manually assigning an ID, make the function automatically assign one, and return it. You can then store it in a named (!) variable and use that variable to refer to the popup, instead of obfuscating meaning behind an arbitrary integer literal (which is just an implementation detail).
auto cakePopup = CreatePopup("Cake?", "Ya", "Na");
if (PopupAnswered(cakePopup,1)) DoStuff();
Popups are all named, and relying on variables over literals should enforce proper scoping and dependency passing (currently you can read/write/modify a popup from anywhere at any time knowing just the integer ID - the dependency is passed through the programmer, which is not ideal, more formal/documented approach scales better).
If you want more flexibility, just do what you would do with any other regular object - declare it in a higher scope (even a global if that is what is required to fully replace your current approach, the point is to use the most local scope possible to minimize clutter), or store handles in a map (as in string=>handle type) or other indirection mechanism instead of a named variable (if you want to load the popups from a data file at runtime / let the user create their own / procedurally generate them - all could use something like that).
The actual type of the handle is less critical (use auto, and a using-declaration so you can easily change it in one place), so it becomes easier to turn it into a struct/class if you want to add more functionality (thats why I used "auto" for the type). An integer is fine, but sometimes adding some additional context, debugging data, or member functions is useful (keeping the type ambiguous leaves the door open for such additions).
Enums could be used to index into a map (if you find you need that indirection layer) of these runtime-allocated handles. Dont use enums to directly name specific handle values at compile time - it requires allocating handles at compile time (which is unnecessary, complex, and limiting, if you already have the more flexible runtime allocation as a foundation).
So you have the basic runtime handle allocation (create any number of popups at any time), and then you can have more than one tool for managing and passing those around (variables in various scopes, containers/maps, function parameters...). You can even use your current integer-indexed approach, just create an array/vector/map of handles somewhere (as in PopupAnswered(popupHandles[13])).