Actual code is more complex but I was able to reduce it to this example.
Everything works fine until I try to take a pointer to MyPackets_t::types (uncomment call to foo() in main() )
At this point in order for the application to link, types requires a definition.
I'm struggling with correct syntax for the definition. Commented out template... should do the trick. However it generetes an error " template arguments to 'PacketCollection::types' do not match original template".
Trying something like this - template<> constexpr int PacketCollection::types[]; - causes another linker error as though variable is being used in that line rather than declared.
I've tried using MyPackets_t instead of PacketCollection - same results.
If I make packet collection non-templated then everything compiles and runs as expected.
I feel that I'm either missing something extremely basic here or there is a bug in the compiler. I get this behavior with gcc 4.8 and 4.9.
Clang 3.5 has a sligtly different take on the situation: declaration of constexpr static data member 'types' requires an initializer.
The only workaround that I've found so far was to use
static constexpr std::array<int, 2> types() { return {1,2}; }
instead, but I don't like this solution. If variable workes in non-templated version (using the initializer from header) it should also work for templated one.
#include <iostream>
using namespace std;
class Packet_A
{
public:
static constexpr int TYPE = 1;
};
class Packet_B
{
public:
static constexpr int TYPE = 2;
};
template <typename T> class PacketCollection
{
public:
static constexpr size_t size = 2;
static constexpr int types[size] { 1, 2 };
};
typedef PacketCollection<Packet_A> MyPackets_t;
//template<typename T> constexpr int PacketCollection<Packet_A>::types[PacketCollection<Packet_A>::size];
void foo(const int* bar, size_t size)
{
if (size >= 2)
{
cout << bar[0] << bar[1];
}
}
int main(int argc, char* argv[])
{
cout << Packet_A::TYPE;
cout << MyPackets_t::types[0];
//foo(MyPackets_t::types, MyPackets_t::size);
return 0;
}