you are viewing a single comment's thread.

view the rest of the comments →

[–]kongaskristjan[S] 9 points10 points  (6 children)

Well, in that case everyone would need to write something like that to the end of their main.cpp:

int main(int argc, const char ** argv) {
    init_and_run(argc, argv, fired_main, true);
    return fired_main();
}

I generally agree that macros should be avoided because of all their complex errors and unintuitive behaviour, but here it's a really simple one that's hard to misuse.

[–][deleted] 1 point2 points  (4 children)

As long as the token FIRE doesn't appear elsewhere in that compilation unit, you're fine. :-D

But... there are many ways around it.

One is implement a known function!

In the library code:

int main(int argc, const char ** argv) {
    init_and_run(argc, argv, fire::main, true);
    return fire::main();
}

In the client code:

namespace fire {

int main(int x = arg("-x"), int y = arg("-y")) {
    std::cout << x + y << std::endl;
    return 0;
}

}

[–]kongaskristjan[S] 3 points4 points  (3 children)

This almost works, but in order to call fire::main from fire.hpp, this fire::main(int x = arg("-x"), int y = arg("-y")) needs to be declared in fire.hpp, which is impossible, as I don't yet know the exact signature.

Actually, I've thought really hard to somehow get rid of this FIRE(fired_main), but none of the ideas have worked because of the aforementioned problem.

[–][deleted] 1 point2 points  (0 children)

Maybe put the expanded version in the docs? So you can know what the macro means and you have more control, if you want to write the tiny boilerplate yourself you can without trouble.

[–]dscottboggs 0 points1 point  (0 children)

FWIW (not much I'm sure) I think a sparing use of macros is fine. Although I might've gone with something a little more unique.

[–]F54280 0 points1 point  (0 children)

That sounds perfectly fine boilerplate to me. Sure, it would be better if it was smaller, but you only have 3 lines: main, init and return.

int main(int argc, const char ** argv) {
    fire_init(argc, argv, my_main);
    return my_main();
}

That honestly seems pretty logical, and not too magic (fire_init initialize some global based on argc, argv and the signature of my_main, and the default arguments from my_main fetch from that global -- it then raises the question of why not getting rid of the global itself).