I'm trying to represent some meta information in a structured way (i.e. using a class). It's header-only and I need to support c++11 so can't use inline variables. I've come up with a couple of potential solutions but each has its drawbacks. Any suggestions would be much appreciated though just pointing on how to make "alternative B" to compile would be a great solution for me.
SthInfo::fieldA
is used as an argument to a templated Processor<Type>::work(field)
which :
- checks that the "container type" matches this processor
- and uses the ID together with other non-relevant args do some internal logic
Alternative A - working but templated ID
#include <type_traits>
template <typename Container, int ID>
class FieldInfo {
public:
static constexpr int id = ID;
};
template <typename T>
class Processor {
public:
template <typename Container, int ID>
void work(FieldInfo<Container, ID> field) {
static_assert(std::is_same<Container, T>::value, "Given field can't be processed - container type mismatch");
// some business logic using the ID, i.e. accessing `field.id`
int id = field.id;
}
};
struct Sth {/* contains fieldA and fieldB - just as an example */};
// SthInfo holds meta-information about fields in Sth
struct SthInfo {
static constexpr FieldInfo<Sth, 1> fieldA{};
};
int main() {
Processor<Sth> processor;
processor.work(SthInfo::fieldA);
}
This works (compiles and links) fine on Linux and Windows. However, Is there a way to avoid the ID
constant in the template and have it as a field in the FieldInfo
class? Any other improvement ideas?
Alternative B - broken - won't link
I've tried changing to the following code but it doesn't link on Linux (but does on Windows...) with undefined reference to SthInfo::fieldA
:
#include <type_traits>
template <typename Container>
class FieldInfo {
public:
const int id;
};
template <typename T>
class Processor {
public:
template <typename Container>
void work(FieldInfo<Container> field) {
static_assert(std::is_same<Container, T>::value, "Given field can't be processed - container type mismatch");
// some business logic using the ID, i.e. accessing `field.id`
int id = field.id;
}
};
struct Sth {/* contains fieldA and fieldB - just as an example */};
// SthInfo holds meta-information about fields in Sth
struct SthInfo {
static constexpr FieldInfo<Sth> fieldA{1};
};
int main() {
Processor<Sth> processor;
processor.work(SthInfo::fieldA);
}
Alternative C - constexpr function - not so nice to use.
Changing SthInfo::fieldA
to a constexpr function helps but then you have to use ()
when using in the app code...
#include <type_traits>
template <typename Container>
class FieldInfo {
public:
const int id;
};
template <typename T>
class Processor {
public:
template <typename Container>
void work(FieldInfo<Container> field) {
static_assert(std::is_same<Container, T>::value, "Given field can't be processed - container type mismatch");
// some business logic using the ID, i.e. accessing `field.id`
int id = field.id;
}
};
struct Sth {/* contains fieldA and fieldB - just as an example */};
// SthInfo holds meta-information about fields in Sth
struct SthInfo {
static constexpr FieldInfo<Sth> fieldA() { return FieldInfo<Sth>{1}; }
};
int main() {
Processor<Sth> processor;
processor.work(SthInfo::fieldA());
}