In the following code I try to register a singleton instance with a global array that keeps all singletons (in production code I can instantiate different singletons based on template parameters so don't worry about this paradox :) ). What I wanted to know is if I can somehow get the address of to-be return type of the lambda which is ought to be return value optimized anyway, so I can register it with the global entries array.
Here's what I've got:
#include <ranges>
#include <cstdio>
#include <cstdint>
#include <iostream>
namespace rng = std::ranges;
struct MyStruct {
uint32_t a = 0;
};
struct AllStructs {
std::array<MyStruct*, 10> items = { 0 };
std::size_t count = 0;
} g_entries;
auto get_instance() {
static MyStruct instance = []() -> MyStruct{
MyStruct ret{ 15 };
g_entries.items[g_entries.count++] = &ret;
return ret;
}();
return instance;
}
int main() {
[[maybe_unused]] auto instance = get_instance();
std::cout << "my a = " << instance.a << std::endl;
std::cout << "my a from array = " << g_entries.items[0]->a << std::endl;
}
Output:
my a = 15
my a from array = 0
It doesn't work like this at least, as the entry gleaned from the array is still 0. How can I work around this?
Further notes:
NRVO is not mandatory. But you can just take the address of the result object directly:
auto& get_instance() {
static MyStruct instance = []() -> MyStruct {
MyStruct ret{ 15 };
g_entries.items[g_entries.count++] = &instance;
return ret;
}();
// Or if you don't otherwise need `ret`
static MyStruct instance = []{
g_entries.items[g_entries.count++] = &instance;
return MyStruct{ 15 };
}();
return instance;
}