Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Definition of constexpr struct inside class (C++11)

58 views
Skip to first unread message

Marcel Mueller

unread,
Jul 4, 2017, 4:52:58 PM7/4/17
to
The following code demonstrates the issue:


#include <stdio.h>

template <typename ...A>
struct MsgTemplate
{ int ID;
const char* Text;
};

// works
constexpr const struct
{ const MsgTemplate<const char*> SOMETHING_WENT_WRONG =
{ 1001, "Something went wrong: %s" };
// more templates ...
} Templates;


struct MyClass
{
// does not work
constexpr static const struct
{ const MsgTemplate<const char*> SOMETHING_WENT_WRONG =
{ 1001, "Something went wrong: %s" };
// more templates ...
} Templates;
};

template <typename ...A>
inline void Message(const MsgTemplate<A...>& tpl, A... a)
{ printf("Message %i: ", tpl.ID);
printf(tpl.Text, a...);
putchar('\n');
}

int main()
{
Message(Templates.SOMETHING_WENT_WRONG, "some details");
Message(MyClass::Templates.SOMETHING_WENT_WRONG, "some details");
return 0;
}


While ::Templates works as expected MyClass::Templates does not compile.

gcc complains:

test9.cpp:22:5: error: constexpr static data member 'Templates' must
have an initializer
} Templates;


I tried several variants, with a (trivial) constexpr constructor, with
an initializer and so on but nothing worked.

What is missing?


Marcel

Marcel Mueller

unread,
Jul 9, 2017, 12:24:40 PM7/9/17
to
I have found a work around:


#include <stdio.h>

template <typename ...A>
struct MsgTemplate
{ int ID;
const char* Text;
};

static constexpr const struct MyClassTemplates
{ const MsgTemplate<const char*> SOMETHING_WENT_WRONG =
{ 1001, "Something went wrong: %s" };
// more templates ...
} MyClassTemplates;

struct MyClass
{
static constexpr const struct MyClassTemplates Templates =
MyClassTemplates;
};


But I have no idea why this additional symbol fixes the problem.
Compiler-Bug?


Marcel

Öö Tiib

unread,
Jul 9, 2017, 7:17:20 PM7/9/17
to
I don't think so. Some C++ compilers permit anonymous structs as an
extension to standard C++ language. So what you wrestle there with
seems most likely to be that extension. You made the struct not
anonymous and that works better.

Manfred

unread,
Jul 13, 2017, 1:31:30 PM7/13/17
to
Here you moved the MyClassTemplates struct definition out of MyClass,
and defined a global object MyClassTemplates as well (poor choice of
object and class with the same name)
What is left within MyClass is a static constexpr declaration, with its
initializer in place, and type which is defined at the namespace level.

> Compiler-Bug?

Not at this stage.

The gcc error is correct, in the sense that the initializer is missing
in your original code.
However, if you modify it as:

struct MyClass
{
// does not work
constexpr static const struct
{ const MsgTemplate<const char*> SOMETHING_WENT_WRONG =
{ 1001, "Something went wrong: %s" };
// more templates ...
} Templates{}; // <== note the {} initializer
};

then you get a more obscure error:
constexpr.cc:26:15: error: constructor required before non-static data
member for ‘MyClass::<anonymous struct>::SOMETHING_WENT_WRONG’ has been
parsed
} Templates{};
^

and the same happens if you get rid of the <anonymnous struct>:

struct MyClass
{
// does not work
constexpr static const struct MyT
{ const MsgTemplate<const char*> SOMETHING_WENT_WRONG =
{ 1001, "Something went wrong: %s" };
// more templates ...
} Templates{}; // <== note the {} initializer
};

At this point, I /think/ the error is related to the fact that static
constexpr initializers are best handled at the namespace level (in fact,
if I understand what you are trying to do here a namespace could be an
option) - Bjarne writes (TC++PL p.506):
"However, for a few simple cases, it is possible to initialize a static
member in the class declaration. ..." and the following text gives more
detail, with which I still can't map an error to the case, though.
Maybe someone else can shed some more light on the puzzle.

>
>
> Marcel

0 new messages