Built-in functions and one definition rule

inline

functions provide something to relax a single definition rule - multiple definitions are allowed, albeit with some restrictions. One wording I found on the internet is

The requirements are that each definition must be the same, that is, it must consist of the same tokens and refer to the same elements.

although I admit that I don't know if this is final. I'm also not sure how strict he is.

I am looking at cases where I create headers with definitions class

and / or inline

which I want to be - #include

possible, whether it compiles to C ++ 03, C ++ 11, or even a later standard. It would be natural to use a macro __cplusplus

to conditionally change the code, but will the ODR be involved? For example, reasonably conditionally:

  • provides nested typedef

    .
  • provides nested class

    .
  • provide motion-related functions.
  • check the function throw()

    or noexcept

    . (This is especially important, since every destructor takes an implicit one noexcept

    in C ++ 11.)
  • check the function constexpr

    .
  • mark the function with override

    and / or final

    .
  • check the function [[noreturn]]

    and / or [[nodiscard]]

    .
  • check the parameter [[maybe_unused]]

    .
  • use [[fallthrough]]

    inside function body.

but which one - if any - is actually allowed if one wants to include libraries #include

such headers need to be compiled under different standards and still be safely used together?

+3


source to share


1 answer


In general, you cannot do this safely. There's only two safe use cases say two class definitions. Trivially, you can just have two separate processes, compiled differently, that link, for example. Common memory. Less trivially, you can use two libraries that define the same character A in two ways, if:

  • the A symbol is only an implementation detail of the library; it cannot be provided by the library and does not appear in any interfaces.
  • On these lines, none of the library header files should transitively include the A header. Therefore, client translation units will not receive any definition of A from the library.
  • the visibility of the A symbol must be marked as closed / hidden.

If you do all of this, then A is really an implementation detail of the library, and you can use multiple libraries that define A differently. If any of these fail, you cannot guarantee that any of the above will work (although some will).



One of the most surprising results for those unfamiliar with the linker is that if lib1 and lib2 use the character A, even if they stop any leaks through headers, if the visibility of A is public, then one definition of A will be used in both libraries. So either lib2 will use lib1's definition or vice versa. This will lead to UB quite easily.

On * nix systems, public visibility is the default, so you will definitely need to hide from the character, which is a little secret.

0


source







All Articles