Declare a reference and initialize later?
C++ReferenceC++ Problem Overview
I have a reference to some class MyObject
, but the exact object depends on a condition. I want to do something like this:
MyObject& ref;
if([condition])
ref = MyObject([something]);
else
ref = MyObject([something else]);
I cannot do this right now because the compiler does not allow me to declare but not initialize a reference. What can I do to achieve my goal here?
C++ Solutions
Solution 1 - C++
You need to initliaze it. But if you would like to conditionally initialize it, you can do something like this:
MyObject& ref = (condition) ? MyObject([something]) : MyObject([something else]);
Solution 2 - C++
AFAIK this can't be done with a reference. You'd have to use a pointer:
MyClass *ptr;
if (condition)
ptr = &object;
else
ptr = &other_object;
The pointer will act similar to a reference. Just don't forget to use ->
for member access.
Solution 3 - C++
You can't do this. References must be bound to something, you may not like it but it prevents a whole class of errors, because if you have a reference you can always assume it's bound to something, unlike a pointer which could be null.
Your example code wouldn't work anyway because you attempt to bind a non-const reference to a temporary object, which is invalid.
Why do you need it to be a reference anyway? One solution would be to ensure your type has an inexpensive default constructor and can be efficiently moved, then just do:
MyObject obj;
if([condition])
obj = MyObject([something])
else
obj = MyObject([something else]);
Otherwise you'd have to put the conditional code in one or more functions, either:
const MyObject& ref = createObject([condition]);
or
const MyObject& ref = [condition] ? doSomething() : doSomethingElse();
Note that both these versions use a const reference, which can bind to a temporary, if the object must be non-const, then again stop trying to use a reference:
MyObject obj = createObject([condition]);
This will probably be just as efficient as what you were trying to do, thanks to the return value optimization
Solution 4 - C++
What I like to do is a lambda that's immediately executed.
Let's suppose we want a const std::string& to a variable from under the map - if map does not contain given key - we want to throw.
int main()
{
std::map<std::string, std::string> myMap = {{"key", "value"}};
const std::string& strRef = [&]()->const std::string& {
try {
return myMap.at("key"); // map::at might throw out_of_range
}
catch (...) {
// handle it somehow and/or rethrow.
}
}(); // <- here we immediately call just created lambda.
}
You could also use std::invoke() to make it more readable (since C++17)
int main()
{
std::map<std::string, std::string> myMap = {{"key", "value"}};
const std::string& strRef = std::invoke([&]()->const std::string& {
try {
return myMap.at("key"); // map::at might throw out_of_range
}
catch (...) {
// handle it somehow and/or rethrow.
}
});
}
Solution 5 - C++
In C++, you can't declare a reference without initialization. You must initialize it.
Solution 6 - C++
Short answer: you don't.
Marginally longer answer: do something like this:
MyObject& getObject()
{
if([condition])
return [something]
else
return [something else];
}
MyObject& ref = getObject();
Usual disclaimers regarding references apply of course.
Solution 7 - C++
MyClass *ptr;
if (condition)
ptr = &object;
else
ptr = &other_object;
MyClass &ref = *ptr;
Solution 8 - C++
use a static dummy as place holder. or std::optional with reference_wrapper.
static X placeHolder_;
std::reference_wrapper<X> ref = placeHolder_;
std::optional<std::reference_wrapper<X>> ref ;
Solution 9 - C++
if([condition]) MyObject& ref = MyObject([something]); else MyObject& ref= MyObject([something else]);
Solution 10 - C++
I usually do this (C++ 11 or later):
std::shared_ptr<ObjType> pObj;
if(condition)
pObj = std::make_shared<ObjType>(args_to_constructor_1);
else
pObj = std::make_shared<ObjType>(args_to_constructor_2);
which is clean and allows using object definition with (possibly different) constructions, a thing you can't do directly with pointers as the compiler will complain from using temporary objects.
Solution 11 - C++
You can use a template which does not require initialization until you actually use it.
template <uint8_t c>
uint8_t& ref;
void setup()
{
uint8_t a=1;
uint8_t b=2;
if(true)
ref<1> = a;
else
ref<1> = b;
}
Some old IDEs may mark it as an error but it will finely pass the compilation.
Solution 12 - C++
You can use "extern" keyword: first time (assume, in header file) you can declare your variable preceding declaration with "extern" keyword. Later (in source file) you repeat declaration without "extern" and assign value to it.