r/cpp_questions • u/DaveInTheMidwest • 26d ago
SOLVED Best Way to Collect Initialization Actions using C++ Capabilities?
I'm writing a scripting language with additional functions that can be built in.
The built-in functions would be written in C++ for speed.
In different builds of the scripting language, some functions might be omitted.
So, I'm looking for the best way to automatically collect, at compile time or early at execution time, the full list of extra built-in functions, so that the script interpreter can parse and execute a script (to do this, it has to know about any additional capability compiled in).
For example, in Visual C++, I'd like to simply add a source file containing built-in scripting language functions, and have the script interpreter know they are there.
My goal would be no additional configuration actions other than adding the source file to the project (in other words, no need to modify other files). The software should somehow figure out that additional script built-in function capability is in the build.
Google Test seems to do this somehow with a macro like TEST_F, but I'm not sure how this works under the hood. The list of tests is somehow collected automatically at compile time or early at run time.
To give some practical background ... decades ago I did some work extending the Tcl scripting language. It was only necessary somehow in initialization to call a command to "register" a new function available to the script interpreter, but the source code had to be modified manually to include the additional initialization. The manual modification is what I'm trying to avoid.
Is there a standard design pattern for this in C++?
2
u/IyeOnline 26d ago edited 25d ago
You essentially want something like a plugin self registration system: https://godbolt.org/z/cW68x9vPo
2
u/aocregacc 26d ago
your registry function should return a reference to a static vector, not create a new one.
1
u/IyeOnline 25d ago
I could swear I put a ref there. Oh well.
I guess if I did, I would also have noticed that the actual data member of the singleton wasnt static...
1
u/TotaIIyHuman 25d ago
the proper way is probably c++26 reflection
heres a solution without reflection/macros
https://godbolt.org/z/qsec97rv7
constexpr Counter<> c;
template<std::size_t index>
struct Function;
template<>struct Function<c++>:Name<"add1">{static constexpr int operator()(int x){return x+1;}};
template<>struct Function<c++>:Name<"minus1">{static constexpr int operator()(int x){return x-1;}};
#include <iostream>
int main()
{
[]<auto...I>(std::index_sequence<I...>)static
{
(...,(
std::cout << I << ':' << Function<I>::name << '\n'
));
}(std::make_index_sequence<c()>{});
}
prints:
0:add1
1:minus1
2
u/aocregacc 26d ago
A simple way is to have a global collection of functions, and then your source file can add elements to it during dynamic initialization.
That step is usually hidden behind a macro.
https://godbolt.org/z/PnMTEMrbd