2

Complete (not)working example:

struct s { int i; };

template<const s* _arr>
class struct_array
{
public:
    static constexpr auto arr = _arr[0]; // works
    template<int >
    struct inner // line 9, without this struct, it works
    {    
    };
};

constexpr const s s_objs[] = {{ 42 }};

int main()
{
    struct_array<s_objs> t_obj;
    return 0;
}

Compiled like this:

g++ -std=c++11 -Wall constexpr.cpp -o constexpr

I get a running program with ideone's gcc 4.8.1, but 4.7.3 prints this to me:

constexpr.cpp: In instantiation of ‘class struct_array<((const s*)(& s_objs))>’:
constexpr.cpp:18:30:   required from here
constexpr.cpp:9:16: error: lvalue required as unary ‘&’ operand
constexpr.cpp:9:16: error: could not convert template argument ‘(const s*)(& s_objs)’ to ‘const s*’

The last two lines are repeated 3 times. What's the reason, and is there any workaround to use my code on gcc 4.7.3?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Johannes
  • 2,901
  • 5
  • 30
  • 50
  • I strongly suggest you try using a new compiler and avoid stupid workarounds for compiler bugs. Although that might not be very feasible in all situations. – rubenvb Feb 06 '14 at 09:30

1 Answers1

1

This seems to be a compiler bug to me.

I tried you example on gcc 4.1.2 (codepad), and you have to explicitely note the variable as having external linkage (const imply internal linkage unless specified otherwise, the following code is C++03):

struct s { int i; };

template<const s* _arr>
class struct_array
{
public:
    static const s arr;
    template<int >
    struct inner
    {    
    };
};

template<const s* _arr>
const s struct_array<_arr>::arr = _arr[0];

// Notice the 'extern'
extern const s s_objs[] = {{ 42 }};

int main()
{
    struct_array<s_objs> t_obj;
    return 0;
}

I also have it working on gcc 4.8.1 without C++11 enabled.

So, the workaround is:

change

constexpr const s s_objs[] = ...;

to

extern const s s_objs[] = ...;

Live example here.

If you want the variable to be a static class member, then you have to specify it to have external linkage:

struct data
{
    static const s s_objs[1];
};

extern const s data::s_objs[1] = {{ 42 }};

This gives me a warning on gcc 4.7, not on 4.8. Also it doesn't compile on Rise4Fun. So, I'm not sure whether this is pure standard or a bug in one of the compiler.

Synxis
  • 9,236
  • 2
  • 42
  • 64
  • Wow, thanks! What would the declaration be if `s_objs` should be a static class member (of some class) instead of a global variable? Is this still possible? My compiler says that `extern` and `static` were conflicting... – Johannes Feb 06 '14 at 15:30