简体   繁体   中英

Undefined reference to static constexpr member only used by value

I was trying to create a clever class containing a font style. Before this consisted of 3 enums with bit-wise compatible values (each set of values did not had overlapping bits with the other enums) so you could do FontStyle::LEFT | FontStyle::TOP FontStyle::LEFT | FontStyle::TOP

But clang warned me about combining unrelated enums and yes I've seen possible bugs here: FontStyle::LEFT | FontStyle::RIGHT FontStyle::LEFT | FontStyle::RIGHT did set both bits. So I reworked the class using a helper class for the former enums and templates to match correct values. But now I'm getting linker errors for clang on Debug builds about undefined reference to my static constexpr members.

Looking at Undefined reference error for static constexpr member suggests, that the value is ODR-used, but I'm not using any references.

When does a static constexpr class member need an out-of-class definition? this then pointed me to the implicit copy constructor of my helper class which is the issue.

Is there any chance I can avoid the out-of-class definitions in C++14 (C++17 already allows to omit them) and Debug builds (Ctors are optimized away in Release and hence no undefined references)?

Related code :

#include <array>
#include <cstdint>

namespace detail {
template<unsigned T_index>
struct FontStylePart
{
    constexpr FontStylePart(uint8_t val) : value(val) {}
    uint8_t value;
};
} // namespace detail

class FontStyle
{
    static constexpr unsigned AlignH = 0;
    static constexpr unsigned AlignV = 1;

public:
    constexpr FontStyle() = default;

    template<unsigned T_index>
    constexpr FontStyle(detail::FontStylePart<T_index> style) : FontStyle()
    {
        value[T_index] = style.value;
    }

    /// Horizontal align
    static constexpr detail::FontStylePart<AlignH> LEFT = 0;
    static constexpr detail::FontStylePart<AlignH> RIGHT = 1;
    static constexpr detail::FontStylePart<AlignH> CENTER = 2;

    /// Vertical align
    static constexpr detail::FontStylePart<AlignV> TOP = 0;
    static constexpr detail::FontStylePart<AlignV> BOTTOM = 1;
    static constexpr detail::FontStylePart<AlignV> VCENTER = 2;

private:

    std::array<uint8_t, 3> value = {{0, 0, 0}};
};

int main() {
  FontStyle style = FontStyle::CENTER;
  return 0;
}

The line

FontStyle style = FontStyle::CENTER;

is a ODR use of FontStyle::CENTER .

I tried using

constexpr FontStyle style = FontStyle::CENTER;

but I ran into problems in the constructor. The following works although it's not clear to me whether that is acceptable for your needs.

int main() {
   constexpr auto v = FontStyle::CENTER;
   FontStyle style = v;
   return 0;
}

This transfers the onus of ODR use to constexpr auto v .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM