Compile time C++ constructors? - Page 1
Forum section: electronics / general

author: westfw
author_rank: Super Contributor
timestamp: March 04, 2022, 11:09:41 pm
content: Can I coerce C++ construction of objects to happen at compile time, even for relatively complex objects?In particular, suppose I want to build a linked list of keywords:Code:keyword *listhead = NULL;keyword _if(listhead, "if", process_if);keyword _else(listhead, "else", process_else);keyword _while(listhead, "while", process_while);And I have constructor/object code that looks somewhat like:Code:class keyword {public:const char *text;void (*func)(char *);keyword *next;keyword(keyword *&head, const char *t, void(*f)(char *)) {text = t;func = f;next = head;head = this; // add to beginning of linked list}};In theory, that could all happen at compile time, leaving me with a linked list that could theoretically be "const" and stuck in ROM instead of precious RAM.Is there a way to make this happen?

author: magic
author_rank: Super Contributor
timestamp: March 05, 2022, 08:25:54 am
content: I suppose constexpr constructors may work, but not if the constructor writes to a global variable.You would need to provide a new constructor which takes thenextpointer to embed in the given list element explicitly, start constructing your objects from the tail and finally initializelistheadwith the last object constructed.Same thing could be achieved with manually initialized ordinary structs or, if there is no need to add elements dynamically, just make it an array instead of a list.

author: retiredfeline
author_rank: Frequent Contributor
timestamp: March 05, 2022, 10:35:35 am
content: Write a script to generate an array of structs/classes and their initializers.

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: March 05, 2022, 05:46:26 pm
content: Quote from: westfw on March 04, 2022, 11:09:41 pmEasily achievable in C with its compound literals. C++ is trickier.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 05, 2022, 06:07:12 pm
content: Quote from: magic on March 05, 2022, 08:25:54 amThat would be the most reasonable approach.Or, even if you need a dynamic list, but initialized with some items, just implement a constructor for the list object that takes an array as a parameter to initialize values.I have a hard time seeing the benefit of going through hoops here, but hey, what do I know.

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: March 05, 2022, 07:03:03 pm
content: Quote from: magic on March 05, 2022, 08:25:54 amWell, you can declare an array and still interlink the elements in order to make it conform to list interfaceUsing the current class declarationCode:class keyword {public:const char *text;void (*func)(char *);keyword *next;keyword(keyword *&head, const char *t, void(*f)(char *)) {text = t;func = f;next = head;head = this; // add to beginning of linked list}};keyword *listhead = nullptr;keyword keywords[] = { { listhead, "if", process_if }, { listhead, "else", process_else }, { listhead, "while", process_while } };Sequencing rules guarantee that array elements are constructed left-to-right.Or you can use a POD-class instead and do thisCode:class keyword {public:const char *text;void (*func)(char *);keyword *next;};keyword keywords[] = { { "if", process_if, nullptr }, { "else", process_else, &keywords }, { "while", process_while, &keywords } };keyword *listhead = &keywords;This feels even more "compile-timeish" although in reality both variants are virtually the same.

author: westfw
author_rank: Super Contributor
timestamp: March 05, 2022, 10:35:33 pm
content: QuoteWhat was clear from my original message (especially after the forum software mangled my newlines) was that I want to AVOID having a single declaration of a big keyword table. I want to intersperse the keyword definitions with the code that implements each keyword like:Code:keyword _if(listhead, "if", process_if);void process_if() {// code to process if}keyword _else(listhead, "else", process_else);void process_else() {// code to process else}This makes it easy to add keywords, or leave them out vs conditional compilation, and would make for a cleaner-looking source code (although harder to look at and see which commands are implemented.)C++ run-time constructors would do this just fine, and they build a data structure that is essentially complete and static that COULD have been built at compile-time.QuoteI could settle for that, if there is a way to initialize individual elements of an array at different points of the source code...(I'm pretty sure I could also do this with inline assembly, since assembly macros tend to be much more powerful than C macros. But... eww.)

author: DiTBho
author_rank: Super Contributor
timestamp: March 05, 2022, 10:49:47 pm
content: what are you trying to achieve? An interpreter?

author: westfw
author_rank: Super Contributor
timestamp: March 07, 2022, 08:42:07 am
content: QuoteA memory-efficient CLI parser, actually.Something where if you want to add a new command (keyword), it is relatively easy at the source level, rather than requiring careful editing of complex data structures, tables, and/or case statements.

author: retiredfeline
author_rank: Frequent Contributor
timestamp: March 07, 2022, 09:23:48 am
content: Write a script to scan the file containing the bodies of your functions to generate an array of structs/classes and their initializers to another file. Use a distinctive macro for the function header to make it easy for your script.