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

constexpr array in template class undefined at link time

49 views
Skip to first unread message

Clifford Heath

unread,
Aug 25, 2017, 7:19:45 AM8/25/17
to
Hi there,

I'm returning to C++ after an absence of 15 years,
and discovering the new features. The attached
cut-down code snippet compiles ok, but I an get
undefined symbol on link.

What should I do to resolve this problem?

Clifford Heath.

$ g++ --std=c++11 -o foo foo.cpp
Undefined symbols for architecture x86_64:
"Base<3>::lengths", referenced from:
Base<3>::write(int) in foo-3d4042.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see
invocation)
$

#include <stdio.h>

template <int unused>
class Base
{
public:
static constexpr unsigned char lengths[8] = { 1, 3, 2, 3, 4, 2, 3, 2 };

void write(int x)
{ // dummy function body
printf("%d\n", x+lengths[x]);
}
};

class MyBase : public Base<3>
{
};

int
main()
{
MyBase base;
base.write(2);
}

Bo Persson

unread,
Aug 25, 2017, 10:01:39 AM8/25/17
to
Using C++11 you would have to also define the array to allocate storage
for it. It is static const *integral* types that can (most often) be
only declared in the class declaration.

With C++17 you could get away with that if you declare it `inline
constexpr`.


Bo Persson

Clifford Heath

unread,
Aug 25, 2017, 4:40:35 PM8/25/17
to
Thanks Bo. I had figured that. But this is a template - there doesn't
seem to be anywhere I can put a declaration. How would you write it? I'm
still a bit of a newb with templates.

Clifford Heath.

Alf P. Steinbach

unread,
Aug 25, 2017, 5:53:51 PM8/25/17
to
The ODR has a special rule for static members of class templates.

You can define that member in the header file.


Cheers & hth.,

- Alf


Clifford Heath

unread,
Aug 26, 2017, 1:15:58 AM8/26/17
to
The header file does not define the template instance,
so it cannot define the array.

What's the point of having a template if you have to
redefine its members for each instance?

Thanks, I'll find another way to do it.

Clifford Heath.

Kalle Olavi Niemitalo

unread,
Aug 26, 2017, 1:45:09 AM8/26/17
to
Clifford Heath <no....@please.net> writes:

> The header file does not define the template instance,
> so it cannot define the array.

template <int unused>
constexpr unsigned char Base<unused>::lengths[];

Clifford Heath

unread,
Aug 29, 2017, 12:43:48 AM8/29/17
to
I tried many variations of this. None worked.
It's now a local static in the method that needs it,
instead of beside the enum whose members it matches.
Sigh.

C++ was always a train wreck, but now it's like
someone nuked the intergalactic railway convention.

Öö Tiib

unread,
Aug 29, 2017, 2:06:47 AM8/29/17
to
Oh. Its just a tool. With gcc version 7.2.0 here your first
post code seems to compile and run ... I go try with clang
on mac too.

Öö Tiib

unread,
Aug 29, 2017, 2:10:11 AM8/29/17
to
Also compiled and ran ... with clang 3.8.0.

Juha Nieminen

unread,
Aug 29, 2017, 2:53:34 AM8/29/17
to
Clifford Heath <no....@please.net> wrote:
> template <int unused>
> class Base
> {
> public:
> static constexpr unsigned char lengths[8] = { 1, 3, 2, 3, 4, 2, 3, 2 };
>
> void write(int x)
> { // dummy function body
> printf("%d\n", x+lengths[x]);
> }
> };

This works ok with clang:

//--------------------------------------------------------------------
template <int unused>
constexpr unsigned char Base<unused>::lengths[8];
//--------------------------------------------------------------------

If it doesn't work for your compiler for some reason, try the C++98 way:

//--------------------------------------------------------------------
template <int unused>
class Base
{
public:
static const unsigned char lengths[8];

void write(int x)
{ // dummy function body
printf("%d\n", x+lengths[x]);
}
};

template <int unused>
const unsigned char Base<unused>::lengths[8] = { 1, 3, 2, 3, 4, 2, 3, 2 };
//--------------------------------------------------------------------

Jorgen Grahn

unread,
Sep 2, 2017, 12:26:14 AM9/2/17
to
I haven't kept track of this thread, but noone promised that the C++11
(and beyond) tools would solve /your/ problem. And you're not obliged
to use them all.

You don't have to use /any/ of them. I design my code like I always
have, i.e. the way I know will probably be successful. If a C++11
feature seems to make it easier or better, I'll give it a try. Not
the best way to learn C++11 -- but the best way to get things done!

Constexpr always seemed tricky; hard to know when it's usable, except
in trivial situations.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
0 new messages