项目作者: dtmoodie

项目描述 :
c++ compile time reflection and tools
高级语言: C++
项目地址: git://github.com/dtmoodie/ct.git
创建时间: 2017-01-09T04:13:09Z
项目社区:https://github.com/dtmoodie/ct

开源协议:MIT License

下载


msvc 2017, gcc 5.4, gcc 7.3: Build status

gcc 4.8: Build Status

ct is a collection of useful compile time utilities for c++. It originally started as a collection of cool functions that then morphed into a set of tools useful for compile time reflection.

An example of ct’s awesome compile time capabilities can be seen with this quick example:

  1. #include <ct/reflect.hpp>
  2. #include <ct/reflect/print.hpp>
  3. #include <iostream>
  4. struct MyStruct
  5. {
  6. REFLECT_INTERNAL_BEGIN(MyStruct)
  7. REFLECT_INTERNAL_MEMBER(float, member_a, 1.0)
  8. REFLECT_INTERNAL_MEMBER(float, member_b, 2.0)
  9. REFLECT_INTERNAL_MEMBER(float, member_c, 3.0)
  10. REFLECT_INTERNAL_END;
  11. };
  12. int main()
  13. {
  14. MyStruct my_struct;
  15. std::cout << my_struct << std::endl;
  16. }

This will produce the following:

  1. (member_a: 1.0 member_b: 2.0 member_c: 3.0)

The above will automatically generate the std::ostream& operator<< for MyStruct. ct also has facilities to generate load and save functions for cereal, data hashing, object hashing, and python bindings are on the way.

Likewise json serialization is trivial using cereal.

  1. #include <ct/reflect/cerealize.hpp>
  2. #include <cereal/archives/json.hpp>
  3. int main()
  4. {
  5. MyStruct my_struct;
  6. cereal::JSONOutputArchive ar(std::cout);
  7. ar(my_struct);
  8. }

The above will produce the following:

  1. {
  2. "value0": {
  3. "member_a": 1.0,
  4. "member_b": 2.0,
  5. "member_c": 3.0
  6. }
  7. }

Metadata can be added to each field

  1. using Description = ct::metadata::Description;
  2. struct MyStruct
  3. {
  4. REFLECT_INTERNAL_BEGIN(MyStruct)
  5. REFLECT_INTERNAL_MEMBER(float, member_a, 1.0, Description("Member a description"))
  6. REFLECT_INTERNAL_MEMBER(float, member_b, 2.0, Description("Member b description"))
  7. REFLECT_INTERNAL_MEMBER(float, member_c, 3.0, Description("Member c description"))
  8. REFLECT_INTERNAL_END;
  9. };

Then the struct can be used with boost program options to load values from the command line.

  1. ct::po::options_description desc;
  2. ct::registerOptions(my_struct, desc);
  3. std::cout << desc << std::endl;
  4. ct::po::variables_map vm;
  5. ct::po::store(ct::po::parse_command_line(ac, av, desc), vm);
  6. ct::po::notify(vm);
  7. ct::readOptions(my_struct, vm);

The std::cout << desc << std::endl call will produce the following:

  1. --member_c arg (=3) Member c description
  2. --member_b arg (=2) Member b description
  3. --member_a arg (=1) Member a description

The macros used in MyStruct can also be expanded to just a few lines for projects disallowing macro usage. The following is equivalent to the previous MyStruct.

  1. struct MyStruct
  2. {
  3. float member_a = 1.0;
  4. float member_b = 2.0;
  5. float member_c = 3.0;
  6. constexpr static auto getPtr(Indexer<0>)
  7. {
  8. return makeMemberObjectPointer("member_a", &MyStruct::member_a, Description("Member a description"));
  9. }
  10. constexpr static auto getPtr(Indexer<1>)
  11. {
  12. return makeMemberObjectPointer("member_b", &MyStruct::member_b, Description("Member b description"));
  13. }
  14. constexpr static auto getPtr(Indexer<2>)
  15. {
  16. return makeMemberObjectPointer("member_c", &MyStruct::member_c, Description("Member c description"));
  17. }
  18. static constexpr const ct::index_t NUM_FIELDS = 3;
  19. };

Furthermore the reflection metadata does not need to be embedded into a type, instead it can be declared externally as such:

  1. namespace ct
  2. {
  3. REFLECT_BEGIN(MyStruct)
  4. PUBLIC_ACCESS_WITH_METADATA(member_a, Description("Member a description"))
  5. PUBLIC_ACCESS_WITH_METADATA(member_b, Description("Member b description"))
  6. PUBLIC_ACCESS_WITH_METADATA(member_c, Description("Member c description"))
  7. REFLECT_END;
  8. }

Lastly properties with get and set methods are supported seamlessly the same as publically accessible data, and member functions can be reflected about.

Enums are supported as well as standard enums and bitset enums.

  1. ENUM_BEGIN(MyEnum, uint32_t)
  2. ENUM_VALUE(kVALUE0, 0)
  3. ENUM_VALUE(kVALUE1, 1)
  4. ENUM_VALUE(kVALUE2, 2)
  5. ENUM_VALUE(kVALUE3, 3)
  6. ENUM_END;
  7. MyEnum val = MyEnum::kVALUE0;
  8. std::cout << val << std::endl;
  9. val = ct::fromString("kVALUE3");
  10. std::cout << val << std::endl;

Will produce the following:

  1. kVALUE0
  2. kVALUE3

Bitset enums are supported as follows:

  1. BITSET_BEGIN(Bitset, int)
  2. ENUM_VALUE(v0, 0)
  3. ENUM_VALUE(v1, 1)
  4. ENUM_VALUE(v2, 2)
  5. ENUM_VALUE(v3, 3)
  6. ENUM_VALUE(v4, 4)
  7. ENUM_VALUE(v5, 5)
  8. ENUM_END;
  9. ct::EnumBitset<Bitset> val = ct::bitsetFromString<Bitset>("v0|v2|v4");
  10. std::cout << val << std::endl;
  11. // Can be used in code as:
  12. if(val.test(Bitset::v0)){
  13. ...
  14. }
  15. if(val.test(Bitset::v2)){
  16. ...
  17. }
  18. ...

Will produce the following:

  1. v0|v2|v4