0

I have to port some code from Microsoft Visual Studio Compiler to clang. Which pulled some nerf of me. Because I have to make sure, that the code still is compileable/linkable with MVSC. Following code is the corpus delicti. Important is, I cannot split the code into src and header file.

Compiler: 6.0.0-1ubuntu2 and Visual Studio 2015

C++: version 14

OS: Ubuntu 18.04 and Windows 10/7

The code is in a header-file. I include it in several src-files.

CODE:

#ifndef GLOBAL_SETTINGS_
#define GLOBAL_SETTINGS_

#include <cstdint>

namespace global {
    enum resolution {
        Hz,
        kHz,
        MHz
    };

    template<resolution T>
    struct sys_clk
    {
        static const double frequency;
    };

#define SYS_CLK_FREQ (115.0e6)

    template<> const double sys_clk<Hz>::frequency = SYS_CLK_FREQ;
    template<> const double sys_clk<kHz>::frequency = SYS_CLK_FREQ/1.0e3;
    template<> const double sys_clk<MHz>::frequency = SYS_CLK_FREQ/1.0e6;

#undef SYS_CLK_FREQ

} // namespace global

#endif /* GLOBAL_SETTINGS_ */

This compiles just fine, but the linker finds himself an unsolvable situation.

LINKER ERROR:

multiple definition of `global::sys_clk_scon<(global::resolution)0>::frequency'
multiple definition of `global::sys_clk_scon<(global::resolution)1>::frequency'
multiple definition of `global::sys_clk_scon<(global::resolution)2>::frequency'

QUESTION:

How is this linker error solvable, so it compiles in MVSC and clang?

5
  • Hack-ish solution: Make one of the .cpp files this is included in the "primary" one. In there, #define XYZ or similar before including GlobalSettings.h and then wrap the explicit instantiations in #ifdef XYZ. But this is just a terrible way to emulate using a dedicated .cpp file. Can you elaborate why this is not actually an option? Commented Sep 10, 2019 at 8:56
  • 1
    If you find any way to switch to C++17, you can declare frequency inline. clang should support, you might compile conditionally (#if __cplusplus > [...]). Commented Sep 10, 2019 at 8:59
  • @Aconcagua I tried that at first, but switching to C++17 is no option, sadly Commented Sep 10, 2019 at 9:01
  • C++17 for clang, and as is (C++14) for MSVC? Something like #if __cplusplus > [...] inline # endif static const ...? Commented Sep 10, 2019 at 9:23
  • Oh, yeah. that sounds like an usable approach =) Commented Sep 10, 2019 at 9:26

1 Answer 1

4

Instead of specializing just the static variable, specialize the whole class. This will allow you to make the variables constexpr, and thus eliminate the need to define them in any TU.

    template<resolution T>
    struct sys_clk;

#define SYS_CLK_FREQ (115.0e6)

    template<> struct sys_clk<Hz> {
      static constexpr double frequency = SYS_CLK_FREQ;
    };
    template<> struct sys_clk<kHz> {
      static constexpr double frequency = SYS_CLK_FREQ/1.0e3;
    };
    template<> struct sys_clk<MHz> {
      static constexpr double frequency = SYS_CLK_FREQ/1.0e6;
    };

#undef SYS_CLK_FREQ

The caveat is that you must make sure they aren't odr-used (have their address taken or a reference bound to them). Because then your multiple definitions error will turn into an unresolved definition error.

Sign up to request clarification or add additional context in comments.

3 Comments

In case they are odr-used, definitions can be put in one source file, like template <> constexpr double sys_clk<Hz>::frequency;. (This still allows the compiler to easily "see" the variable values in all TUs, and possibly apply optimizations like constant folding.)
@aschepler - Well, the premise was that splitting between source and header is not an option. But I confess there isn't a true perfect solution for C++14.
Ah, I missed that. Still, the definitions could be put in one source file which happens to include the header (and is sure to be linked into all appropriate libraries and executables, if multiple).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.