vendredi 3 juillet 2020

constexpr template meta-info variable in c++11

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.

Solution A - working but templated ID

Simplified code example:

library.h:
template <typename Container, int ID>
class FieldInfo {
public:
    static constexpr int id = ID;
};

sth.h:
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{};
  static constexpr FieldInfo<Sth, 2> fieldB{};
};

SthInfo::fieldA is then 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
library.h:
template <typename T>
class Processor {
public:
    template <typename Container, int ID>
    someReturnType work(FieldInfo<Container, ID> field, someMoreArgs) {
        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`
    }
};

app.cpp:
#include "library.h"
#include "sth.h"

// and called like this
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?

Broken solution B - 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:

library.h:
template <typename Container>
class FieldInfo {
public:
    const int id;
};

sth.h:
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};
  static constexpr FieldInfo<Sth> fieldB{2};
}

main.cpp - same as with "Solution A". 

Solution 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...

library.h - same as solution B

sth.h:
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}; }
  static constexpr FieldInfo<Sth> fieldB() { return FieldInfo<Sth>{2}; }
};

app.cpp:
int main() {
   Processor<Sth> processor;
   processor.work(SthInfo::fieldA()); // note fieldA() function call
}

Aucun commentaire:

Enregistrer un commentaire