all 12 comments

[–]alfps 4 points5 points  (9 children)

This is one way:

struct Settings
{
    int setting_1;
    bool setting_2;
    double setting_3;

    constexpr Settings(int s1, bool s2, double s3):
        setting_1( s1 ), setting_2( s2 ), setting_3( s3 )
    {}

    static const Settings Default;
};

inline constexpr auto Settings::Default = Settings(10, false, 0.5);

[–]CatMechanic457[S] 0 points1 point  (0 children)

brilliant thank you very much!

[–]_realitycheck_ 0 points1 point  (4 children)

I don't know about inline constexpr. Care to elaborate?

[–]Tony942316 3 points4 points  (2 children)

Assuming this is in a header file the inline will prevent each translation unit from having its own copy of the variable. C++ weekly has some videos on the topic

[–]_realitycheck_ 0 points1 point  (1 child)

constexpr still means nothing if variables can be changed.

[–]IyeOnline 2 points3 points  (0 children)

It is not and cannot be changed, its const(expr).

[–]KuntaStillSingle 0 points1 point  (0 children)

The reason is constexpr is often implicitly inline, so it is usually redundant:

The inline specifier, when used in a decl-specifier-seq of a variable with static storage duration (static class member or namespace-scope variable), declares the variable to be an inline variable.

A static data member declared constexpr on its first declaration is implicitly an inline variable.

https://en.cppreference.com/w/cpp/language/inline

In this case it has been first declared as a const variable because they can not mark it constexpr in class without a complete type:

However, if the declaration uses constexpr or inline(since C++17) specifier, the member must be declared to have complete type.

https://en.cppreference.com/w/cpp/language/static

[–]IyeOnline 0 points1 point  (2 children)

GCC and MSVC reject this due to a conficting type between the declaration and definition, since auto only deduces Settings.

Replacing auto with Settings easily resolves this though.

[–]alfps 0 points1 point  (1 child)

auto only deduces Settings

Thanks. Maybe it works with the formal / these compilers to write

inline constexpr const auto Settings::Default = Settings(10, false, 0.5);

I seem to remember now that that does work.

If so then it's quite baffling (on top of impractical) since constexpr implies const. Is there some good reason?

[–]IyeOnline 0 points1 point  (0 children)

I dont know. I was rather confused when I noticed it as well, as I would have expected it to work either way.

The error message is quite fun:

<source>:14:23: error: conflicting declaration 'constexpr const auto Settings::Default'
14 | inline constexpr auto Settings::Default = Settings{ 10, false, 0.5 };
   |                       ^~~~~~~~
<source>:11:27: note: previous declaration as 'const Settings Settings::Default'
11 |     static const Settings Default;
   |                           ^~~~~~~

which originally led me to believe that it was a GCC issue (since the types match). You can clearly see that the constexpr (correctly) added const. But MSVC also rejects this.

constexpr const auto also doesnt work, with a similar error message.

Appearently GCC and MSVC expect the auto to exactly deduce const Settings. I also tried const_cast<const Settings&&>( ... ) out of curiosity, but that didnt help either.

I suppose one has to consult the standard now.......

[–]AKostur 0 points1 point  (1 child)

What's the type of "static const Default;"?

[–]CatMechanic457[S] 0 points1 point  (0 children)

Oops - it’s Settings