Why is my global, extern lambda variable not initialized at runtime?

Viewed 264

I am implementing parser combinators by composing C++ lambdas.

For example:

// rule_character.cpp
#include "rule_character.hpp"

LexerRule character_name =
    (make_terminal("alarm") & replace_with("\a")
        | (make_terminal("backspace") & replace_with("\b"))
        | (make_terminal("delete") & replace_with("\x7f"))
        | (make_terminal("escape") & replace_with("\x1b"))
        | (make_terminal("newline") & replace_with("\n"))
        | (make_terminal("null") & replace_with("\0"))
        | (make_terminal("return") & replace_with("\r"))
        | (make_terminal("space") & replace_with(" "))
        | (make_terminal("tab") & replace_with("\t"))) / "character-name";

LexerRule character =
    ((make_terminal("#\\") & ignore_string) +
        (character_name
            | ((make_terminal("x") & ignore_string)
                + (hex_scalar_value & replace_hex_scalar_value))
            | (make_class([](char c) { return true; }, "any-character"))))
        / "character";

where LexerRule is an alias for a std::function type.

Here is the header:

// rule_character.hpp
extern LexerRule character_name;
extern LexerRule character;

In main.cpp, however, a std::bad_function_call is being thrown:

// main.cpp
// When: you try to parse a series of identifier
skip_ws(lex);
// When: you try to parse a string
 std::cout << (void*)(rules::character.target<LexResult (*) (LexerInput&)>() )
        << std::endl;
LexResult result = rules::character(lex);
while (result.is_token()) {
  results.push_back(result);
  skip_ws(lex);
  result = rules::character(lex);
}

But target is 0 or nullptr. Why would this be so even if I'm sure that the two .cpp source files' respective .o object files are being linked? Why is my global lambda left uninitialized?

1 Answers

The problem had to do with static initialization order. Since the lambdas often relied on each other already being initialized in a specific order, the initialization would not happen and the global lambdas would be left in an invalid state, thus causing the std::bad_function_call exceptions at runtime.

To fix the problem, I moved the initialization of the global lambda variables to runtime.

Related