Reputation: 1291
Suppose I had a boost variant instance containing a default initialised value (DataContainer
). After a certain point in the program, it is guaranteed that the variant instance will contain a certain type (float
) before a critical part of the program, but I only have access to the variant instance prior to it being set to this guaranteed type (DataDispatcher::set
).
How can I create a float pointer to the location where the variant instance will be stored? Is it possible? My current attempt in Dispatcher::set
causes a runtime error since the variant does not yet contain the float type.
Thanks
using Variant = boost::variant<std::string, float>;
struct DataContainer {
Variant value; // default initalised
};
class DataDispatcher {
public:
void set(DataContainer* dc) {
// this causes a fpointer to be equal to nullptr because dc->value is a string
// how to fix this?
fpointer = boost::get<float>(&dc->value);
}
// critical part of the program
void dispatch() {
importantCalculation(*val + 5);
}
private:
float* fpointer;
};
int main() {
DataContainer dc;
DataDispatcher dd;
dd.set(&dc); // only have access to variant instance here
dc.val = 1.4252; // guarantee it will contain a float
dd.dispatch(); // critical part
}
Upvotes: 1
Views: 63
Reputation: 393064
How can I create a float pointer to the location where the variant instance will be stored? Is it possible?
That's not reliably possible. It smells like a design issue when you "need" to store a pointer to data before it exists.
The natural solution is to store a reference to the variant instead: Live On Coliru
If you are convinced that the "optimization" of keeping a direct pointer to the float value is significant, you could do that manually:
#include <boost/variant.hpp>
#include <iostream>
#include <string>
void importantCalculation(float v) {
std::cout << "importantCalculation(" << v << ")\n";
}
using Variant = boost::variant<std::string, float>;
struct DataContainer {
Variant value;
};
class DataDispatcher {
public:
void reset() {
_cached = nullptr;
_ref = nullptr;
}
void set(DataContainer const& dc) {
_ref = &dc;
update_cache(); // in case it is already float
}
// critical part of the program
void dispatch() { importantCalculation(get() + 5); }
private:
DataContainer const* _ref = nullptr;
float const* _cached = nullptr;
void update_cache() {
_cached = nullptr;
if (_ref)
if (auto* fp = boost::get<float>(&_ref->value))
_cached = fp;
}
float get() {
if (!_cached)
update_cache();
assert(_cached);
return *_cached;
}
};
int main() {
DataContainer dc;
DataDispatcher dd;
dd.set(dc); // only have access to variant instance here
dc.value = 1.4252; // guarantee it will contain a float
dd.dispatch(); // critical part
// important:
dd.reset();
dc.value = "3.6474";
dc.value = 2.5363;
dd.set(dc); // important
dd.dispatch();
}
Prints
importantCalculation(6.4252)
importantCalculation(7.5363)
Note that other variant implementations might document a guaranteed element storage layout for small element types, and you could then rely on that documented guarantee.
Upvotes: 1