C++ Code that runs immediately when the program is turned on - c++

struct First{
First(){
printf("first");
}
}First;
int main()
{
print("second");
return 0;
}
I know I can control the code that is executed first through the structure.
So I want to use the following code to make it simple through macro.
#define FIRST_INVOKE(NAME,FUNCTION) \
struct NAME \
{ \
NAME() \
{ \
FUNCTION(); \
} \
} NAME;
namespace Foo
{
namespace Bar
{
void FirstFunction()
{
LOGD(LVID, "First");
}
}
}
FIRST_INVOKE(UniqueStructName, Foo::Bar::FirstFunction);
When creating a macro, you must specify the name of the structure. (UniqueStructName)
I want to set this to a name that does not overlap globally automatically.
Namespace and class static functions cannot be included in structure names because :: is required.
Please let me know if there is a good way (I am using Xcode.)

You can automatically generate names based on the line number and use anonymous namespace to avoid multiple definitions across files. E.g, using the following macro:
#define CONCAT_(A,B) A##B
#define CONCAT(A,B) CONCAT_(A,B)
#define NONAME() CONCAT(noname_, __LINE__)
#define FIRST_INVOKE(FUNCTION) \
namespace { \
struct NONAME() \
{ \
NONAME()() \
{ \
FUNCTION(); \
} \
} NONAME(); \
}
This will expand to a noname_X struct, where X is the line-number. This works as long as you do not repeat the macro on the same line.

Related

How can I make a macro handle different types of arguments?

How can I write a macro that does different things based on the type of its arguments?
I have a macro that needs to handle an argument that can have one of two types.
#include <typeinfo>
enum class Coolness { kUndefined, kUncool, kCool };
enum class Tallness { kUndefined, kShort, kTall };
void MakePerson (Coolness coolness, Tallness tallness) {}
// Provide a way to make a person by only providing Coolness or Tallness.
#define MAKE_PERSON(x) \
({ \
if (typeid(x) == typeid(Coolness)) { \
MakePerson(((x)), Tallness::kUndefined); \
} else { \
MakePerson(Coolness::kUndefined, (x)); \
} \
})
int main()
{
MAKE_PERSON(Coolness::kUncool);
MAKE_PERSON(Tallness::kTall);
}
(We could use default arguments here, but in the real code we effectively must use a macro.)
The compiler throws an error on both calls in main:
main.cpp: In function ‘int main()’:
main.cpp:23:43: error: cannot convert ‘Coolness’ to ‘Tallness’ for argument ‘2’ to ‘void MakePerson(Coolness, Tallness)’
MakePerson(Coolness::kUndefined, (x)); \
^
main.cpp:29:3: note: in expansion of macro ‘MAKE_PERSON’
MAKE_PERSON(Coolness::kUncool);
^~~~~~~~~~~
main.cpp:21:45: error: cannot convert ‘Tallness’ to ‘Coolness’ for argument ‘1’ to ‘void MakePerson(Coolness, Tallness)’
MakePerson(((x)), Tallness::kUndefined); \
^
main.cpp:30:3: note: in expansion of macro ‘MAKE_PERSON’
MAKE_PERSON(Tallness::kTall);
^~~~~~~~~~~
(done on https://www.onlinegdb.com/online_c++_compiler)
We can't use __builtin_types_compatible_p as in this question because our compiler doesn't have that.
How can I write a macro that does different things based on the type of its arguments?
Use simple function overloading, don't try to make the macro smarter than it needs to be:
enum class Coolness { kUndefined, kUncool, kCool };
enum class Tallness { kUndefined, kShort, kTall };
void MakePerson (Coolness coolness, Tallness tallness)
{
...
}
inline void MakePerson (Coolness coolness)
{
MakePerson(coolness, Tallness::kUndefined);
}
inline void MakePerson (Tallness tallness)
{
MakePerson(Coolness::kUndefined, tallness);
}
#define MAKE_PERSON(x) \
{ \
// use __FILE__ and __LINE__ as needed... \
MakePerson(x); \
}
int main()
{
MAKE_PERSON(Coolness::kUncool);
MAKE_PERSON(Tallness::kTall);
}
Live Demo
Other suggestions are welcome, but what we eventually did was use a static_cast to tell the compiler what type the arguments are:
#include <typeinfo>
enum class Coolness { kUndefined, kUncool, kCool };
enum class Tallness { kUndefined, kShort, kTall };
void MakePerson (Coolness coolness, Tallness tallness) {}
// Provide a way to make a person by only providing Coolness or Tallness.
// Static cast is used because the compiler fails to typecheck the
// branches correctly without it.
#define MAKE_PERSON(x) \
({ \
if (typeid(x) == typeid(Coolness)) { \
MakePerson(static_cast<Coolness>((x)), Tallness::kUndefined); \
} else { \
MakePerson(Coolness::kUndefined, static_cast<Tallness>((x))); \
} \
})
int main()
{
MAKE_PERSON(Coolness::kUncool);
MAKE_PERSON(Tallness::kTall);
}
...Program finished with exit code 0

std::tuple as member replacement, convenience macro

I recently started using tuples instead of plain class members because I find it convenient to work with them. So my code looks something like this:
class TestClass final {
public:
TestClass() = default;
~TestClass() = default;
public:
template<int M>
auto get()->decltype(std::get<M>(m_private_members)) const {
return std::get<M>(m_private_members);
}
enum PrivateIdx {
count,
use_stuff,
name
};
private:
std::tuple<int, bool, std::string> m_private_members{1, true, "bla"};
};
So this can be used now like:
std::cout << t.get<TestClass::name>()> << std::endl;
This work also fine - the only thing is, adding members can be quite error-prone. One can easily get the access enums wrong by mixing up the order or forgetting a member. I was thinking of a macro style thing like:
PUBLIC_MEMBERS(
MEMBER(int count),
MEMBER(std::string name)
);
This would expand to the tuple and enum code. Problem is, I don't think this can be solved by a macro because it's two different data structures it would have to expand to, right? Also, I must admit, I've never looked into complicated macros.
I was also thinking of a template for solving this, but I could also not come up with a viable solution because enums cannot be generated by a template.
Interesting problem. I'm curious why you'd like to do this. This is something I came up with. Good news: no macros!
The main problem, I think, is that you want to declare identifiers to access members. This cannot be solved with templates, so you have to either a) use macros, or b) somehow declare those identifiers without directly. Instead of using constants/enumerations, I tried to use type names to identify member in get.
I'll start with an example of use:
class User
{
public:
enum class AccessLevel
{
ReadOnly,
ReadWrite,
Admin
};
struct Name : MemberId<std::string> {};
struct Id : MemberId<unsigned> {};
struct Access : MemberId<AccessLevel> {};
template<typename MemberType>
auto& get() { return PrivMembers::getFromTuple<MemberType>(m_members); }
template<typename MemberType>
const auto& get() const { return PrivMembers::getFromTuple<MemberType>(m_members); }
private:
using PrivMembers = MembersList<Name, Id, Access>;
PrivMembers::Tuple m_members;
};
int main()
{
User user;
user.get<User::Name>() = "John Smith";
user.get<User::Id>() = 1;
user.get<User::Access>() = User::AccessLevel::ReadWrite;
return 0;
}
Name, Id and Access are used for identifying elements of m_members tuple. These structures don't have any members themselves. PrivMembers::Tuple is alias for std::tuple<std::string, unsigned, AccessLevel>:
template<typename Type_>
struct MemberId { using Type = Type_; };
template<typename... Types>
struct MembersList
{
using Tuple = std::tuple<typename Types::Type...>;
template<typename T>
static auto& getFromTuple(Tuple& tp) { return std::get<detail::IndexOf<T, Types...>::value>(tp); }
template<typename T>
static const auto& getFromTuple(const Tuple& tp) { return std::get<detail::IndexOf<T, Types...>::value>(tp); }
};
First thing: Tuple alias. I think its self explanatory what happens. Then, there are to overloads for getFromTuple, which is used by User class.
When using MemberId-derived types instead of constants for accessing elements of the tuple, I need to find index of corresponding to given member Id. That what happens in getFromTuple. There's a helper class which does searching:
namespace detail
{
template<typename Needle, typename HaystackHead, typename... Haystack>
struct IndexOf { static constexpr std::size_t value = IndexOf<Needle, Haystack...>::value + 1; };
template<typename Needle, typename... Haystack>
struct IndexOf<Needle, Needle, Haystack...> { static constexpr std::size_t value = 0; };
}
All of this solves the problem of having to maintain indices for each members, as in your original solution. Syntax for declaring member Ids (struct Name : MemberId<std::string> {};) might be bit annoying, but I cannot think about more compact solution.
All of this works with C++14. If you can live with trailing return type for User::get, then you could compile it as C++11.
Here's full code.
Like I said in comment macros are pain to debug. One who does not see how to write some should think twice if to use these at all. OTOH these are relatively straightforward to write when one gets the logic of those.
Note that given is just one way to do it, like with everything there are several.
So macros are like that:
#define GET_NAME(NAME,TYPE,VALUE) NAME
#define GET_TYPE(NAME,TYPE,VALUE) TYPE
#define GET_VALUE(NAME,TYPE,VALUE) VALUE
#define DECLARE_ENUM(PRIVATES) \
enum PrivateIdx { \
PRIVATES(GET_NAME) \
};
#define DECLARE_TUPLE(PRIVATES) \
std::tuple<PRIVATES(GET_TYPE)> m_private_members{PRIVATES(GET_VALUE)};
#define DECLARE_IN_ONE_GO(PRIVATES) \
public: \
DECLARE_ENUM(PRIVATES) \
private: \
DECLARE_TUPLE(PRIVATES)
And usage is like that:
#include <iostream>
#include <tuple>
#include "enum_tuple_macros.h"
class TestClass final {
public:
TestClass() = default;
~TestClass() = default;
#define PRIVATES(MEMBER) \
MEMBER(count,int,1), \
MEMBER(use_stuff,bool,true), \
MEMBER(name,std::string,"bla")
DECLARE_IN_ONE_GO(PRIVATES)
// note that the get can be also generated by DECLARE_IN_ONE_GO
public:
template<int M>
auto get() const -> decltype(std::get<M>(m_private_members)) {
return std::get<M>(m_private_members);
}
};
int main()
{
TestClass t;
std::cout << t.get<TestClass::name>() << " in one go" << std::endl;
}
Seems to work on gcc 8.1.0 i tried.
In the meantime I came up with something using var args...
taken from
[https://stackoverflow.com/questions/16374776/macro-overloading][1]
#define EXPAND(X) X
#define __NARG__(...) EXPAND(__NARG_I_(__VA_ARGS__,__RSEQ_N()))
#define __NARG_I_(...) EXPAND(__ARG_N(__VA_ARGS__))
#define __ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define __RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
// general definition for any function name
#define _VFUNC_(name, n) name##n
#define _VFUNC(name, n) _VFUNC_(name, n)
#define VFUNC(func, ...) EXPAND(_VFUNC(func, EXPAND( __NARG__(__VA_ARGS__))) (__VA_ARGS__))
#define MEMBER_LIST(...) EXPAND(VFUNC(MEMBER_LIST, __VA_ARGS__))
#define MEMBER_LIST3(mem_type1, mem_name1, default_value1)\
\
enum PrivateIdx { \
mem_name1 \
}; \
\
std::tuple<mem_type1> m_private_members{default_value1}
#define MEMBER_LIST6( mem_type0, mem_name0, default_value0,\
mem_type1, mem_name1, default_value1)\
\
enum PrivateIdx { \
mem_name0, \
mem_name1 \
}; \
\
std::tuple< mem_type0, \
mem_type1 > m_private_members{ default_value0, \
default_value1}
..and so on
Works, but imho still not elegant enough. I think I got pointed in the right direction.

Automatic C wrappers for C++ functions

Let's say I have some unspecified type called variant, as well as two functions allowing to convert to/from this type, with the following signature:
struct converter
{
template<typename T>
static variant to(const T&);
template<typename T>
static T from(const variant&);
};
Now, what I'd like to do is create wrappers for arbitrary C++ functions as in the following example:
SomeObject f_unwrapped(const std::string& s, int* x)
{
//... do something with the inputs...
return SomeObject();
}
extern "C" variant f(variant s, variant x)
{
return converter::to<SomeObject>(f_unwrapped(converter::from<std::string>(s), converter::from<int*>(x)));
}
Ideally I'd want the wrapper to be a one-line declaration or macro that would take only the f_unwrapped function and the name f as inputs.
I've tried to wrap the function into a function object, then do the bureaucratic work using variadic templates. While this does work, I don't know how to make the resulting function extern "C".
What is the most idiomatic way of achieving this goal?
If we use the EVAL, helper, Conditional, and map macros from the first two code blocks here.
The map will need to be made more general for our needs.
#define MM1() MM_CALL1
#define MM_NEXT1(Macro,a,...) \
IS_DONE(a)( \
EAT \
, \
OBSTRUCT(COMMA)() OBSTRUCT(MM1)() \
) \
(Macro,a,__VA_ARGS__)
#define MM_CALL1(Macro,a,...) \
Macro(a) \
MM_NEXT1(Macro,__VA_ARGS__)
#define MacroMap1(Macro,...) MM_CALL1(Macro,__VA_ARGS__,DONE)
#define MM2() MM_CALL2
#define MM_NEXT2(Macro,a,...) \
IS_DONE(a)( \
EAT \
, \
OBSTRUCT(COMMA)() OBSTRUCT(MM2)() \
) \
(Macro,a,__VA_ARGS__)
#define MM_CALL2(Macro,a,b,...) \
Macro(a,b) \
MM_NEXT2(Macro,__VA_ARGS__)
#define MacroMap2(Macro,...) MM_CALL2(Macro,__VA_ARGS__,DONE)
We will also want the WithTypes and WithoutTypes from here.
We can define AMACRO to do the job you wanted.
#define AsVariant(param) variant param
#define ConvertFrom(type,param) converter::from<type>(param)
#define HEADDER(type,func,params) type func ##_unwrapped (WithTypes params)
#define WRAPPER(type,func,params) \
extern "C" variant func (OBSTRUCT(MacroMap1)(AsVariant,WithoutTypes params)) \
{ \
return converter::to< type >(func ## _unwrapped( \
MacroMap2(ConvertFrom,IDENT params) \
)); \
}
#define AMACRO(type,func,params) \
EVAL( \
HEADDER(type,func,params); \
WRAPPER(type,func,params) \
HEADDER(type,func,params) \
)
Which will turn this:
AMACRO(SomeObject,f,(const std::string&, s, int*, x))
{
// ... do something with the inputs ...
return SomeObject();
}
Into this (after formatting):
SomeObject f_unwrapped (const std::string& s , int* x );
extern "C" variant f (variant s , variant x )
{
return converter::to<SomeObject>(f_unwrapped(converter::from<const std::string&>(s),converter::from<int*>(x)));
}
SomeObject f_unwrapped (const std::string& s , int* x )
{
return SomeObject();
}
NOTE:
If the const needs removing from the parameter, a conditional, similar to the ISDONE, can be made and added to the ConvertFrom macro.

Compile time generated block in C++

I have a struct in my server that I would like to generate it with macro or template in C++ as it has a lot of redundant things:
struct MyBlock {
void Merge(const MyBlock& from) {
if (apple.HasData()) {
apple.Merge(from.apple);
}
if (banana.HasData()) {
banana.Merge(from.banana());
}
...
}
void Clear() {
apple.Clear();
banana.Clear();
...
}
void Update(const SimpleBlock& simple_block) {
if (simple_block.apple.Updated()) {
apple.Add(simple_block.apple);
}
if (simple_block.banana.Updated()) {
banana.Add(simple_block.banana);
}
...
}
Fruit apple;
Fruit banana;
Animal dog;
Animal cat;
...
}
struct SimpleBlock {
SimpleFruit apple;
SimpleFruit banana;
SimpleAnimal dog;
SimpleAnimal cat;
...;
}
I would like to define more variables in the two blocks like apple and dog. I would also like to define more pairs of such blocks. But it involves a lot of trivial work. So my question is how we can use macro, template or some other C++ features including C++11 to generate these blocks in compile time?
The reason why I don't use collections to store those variable is because MyBlock struct would be passed as a parameter in another template class which would dynamically allocate and release this block in run time. It is actually a thread local block that would be aggregated periodically.
Straightforward enough with preprocessor list iteration:
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_ID(...) __VA_ARGS__
#define M_LEFT(L, R) L
#define M_RIGHT(L, R) R
#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)
#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
//.. extend this to higher numbers with some copy&paste
#define MYBLOCK(...) struct MyBlock { \
void Merge(const MyBlock& from) { \
M_FOR_EACH(BLOCK_MERGE, __VA_ARGS__) \
} \
void Clear() { \
M_FOR_EACH(BLOCK_CLEAR, __VA_ARGS__) \
} \
void Update(const SimpleBlock& simple_block) { \
M_FOR_EACH(BLOCK_UPDATE, __VA_ARGS__) \
} \
M_FOR_EACH(BLOCK_FIELD, __VA_ARGS__) \
}
#define BLOCK_MERGE(F) if (M_ID(M_RIGHT F).HasData()) { \
M_ID(M_RIGHT F).Merge(from.M_ID(M_RIGHT F)); \
}
#define BLOCK_CLEAR(F) M_ID(M_RIGHT F).Clear;
#define BLOCK_UPDATE(F) if (simple_block.M_ID(M_RIGHT F).Updated()) { \
M_ID(M_RIGHT F).Add(simple_block.M_ID(M_RIGHT F)); \
}
#define BLOCK_FIELD(F) M_ID(M_LEFT F) M_ID(M_RIGHT F);
#define SIMPLEBLOCK(...) struct SimpleBlock { M_FOR_EACH(SIMPLE_DECL, __VA_ARGS__) }
#define SIMPLE_DECL(F) M_CONC(Simple, M_ID(M_LEFT F)) M_ID(M_RIGHT F);
#define FIELDS (Fruit, apple),(Fruit,banana),(Animal,dog),(Animal,cat)
MYBLOCK(FIELDS);
SIMPLEBLOCK(FIELDS);
Add the necessary further member variables to FIELDS in the existing format, and they will be added to the structs emitted by MYBLOCK and SIMPLEBLOCK. (Remember to extend M_FOR_EACH with more iterations... easy to to with a few ctrl+c,ctrl+v.)
template <typename SimpleT>
class BlockTemplate
{
public:
void Merge(const BlockTemplate& from) {
if (HasData()) {
Merge(from.simpleData);
}
}
void Update(const SimpleT& simple_block) {
if (simple_block.Updated()) {
Add(simple_block.data);
}
}
protected:
SimpleT simpleData;
};
Now, you can create objects of type BlockTemplate<SimpleFruit>, BlockTemplate<SimpleAnimal> etc. You could also store pointers to all these BlockTemplate objects in a container after having BlockTemplate inherit from an abstract type. Or, better yet, use the new-fangled type-erasure methods - boost::type_erasure::any for example.
EDIT : If you don't want to use the container that way, you could also make BlockTemplate variadic and store a tuple of different(type-wise) SimpleT objects and modify the Merge and Update functions accordingly. The problem with this is that it becomes much harder to track your SimpleT objects - std::tuple doesn't allow you to give names. You would be referring to the values as get<N>(tupleData).
The description of why you don't use a collection sounds like some optimization thing. Have you measured?
Anyway, one simple solution is store pointers to the objects in a collection.
Then you can iterate over the collection.

simulate compile time reflection in C++

I have a following struct:
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
I want to select one of the members by string name in constexpr manner, like
Data instance;
auto& member = getMember(instance, "firstMember");
getMember is constexpr function/struct/macros/whatever in question and expression should be (I want it to be) optimized into simple auto& member = instance.firstMember;. My desire here is to be able to call getMember from another constexpr function, which in turn are computing name of particular member --> some kind of compile time reflection.
I know, there is no reflection in C++, therefore it's OK to register somehow (partially specialize? use some macros magic?) names of members of struct in question, like:
REGISTER_MEMBER(Data, "firstMember", firstMember);
All I want is to have that compile time optimization and do nothing in runtime. Is that possible in C++11 and how?
As noted in the comments, first take a look at BOOST_FUSION_ADAPT_STRUCT (and friends):
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
BOOST_FUSION_ADAPT_STRUCT(
Data,
(std::string, firstMember)
(std::string, secondMember)
(std::string, thirdMember)
)
This turns your Data structure into a sequence usable by Fusion:
#include <boost/fusion/include/at_c.hpp>
int main()
{
Data d = { "firstData", "secondData", "thirdData" };
std::cout << boost::fusion::at_c<0>(d) << std::endl;
}
This prints "firstData". Change the index to refer to the members in order.
There, now we can refer to members at compile-time using a number. But you wanted a name. Also noted in the comments, processing strings is a runtime feature...almost. C++11 gives us constexpr.
It's a bit tricky, but ultimately it looks like this:
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/seq.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <stdexcept>
// and repeat for BOOST_FUSION_ADAPT_TPL_STRUCT, etc...
#define REFLECT_STRUCT(NAME, ATTRIBUTES) \
REFLECT_STRUCT_DETAIL(NAME, \
ATTRIBUTES, \
BOOST_PP_SEQ_POP_FRONT( \
BOOST_PP_CAT( \
/* warning: uses fusion implementation details: */ \
BOOST_FUSION_ADAPT_STRUCT_FILLER_0(0,0)ATTRIBUTES, \
_END))) \
#define REFLECT_STRUCT_DETAIL(NAME, ATTRIBUTES, WRAPPEDATTRIBUTES) \
BOOST_FUSION_ADAPT_STRUCT(NAME, ATTRIBUTES) \
\
namespace detail \
{ \
namespace BOOST_PP_CAT(reflect_, NAME) \
{ \
template <int N> \
struct member_name; \
\
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_STRUCT_DETAIL_MEMBER_NAME, \
BOOST_PP_EMPTY, \
WRAPPEDATTRIBUTES) \
\
template <int N> \
constexpr bool member_match_index(const std::size_t index, \
const char* const str, \
const std::size_t len) \
{ \
return index == len || \
(member_name<N>::value()[index] == str[index] \
&& member_match_index<N>(index + 1, str, len)); \
} \
\
template <int N> \
constexpr bool member_match(const char* const str, \
const std::size_t len) \
{ \
return len == member_name<N>::value_length \
&& member_match_index<N>(0, str, len); \
} \
\
constexpr int find_member(const char* const str, \
const std::size_t len) \
{ \
return BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(WRAPPEDATTRIBUTES), \
REFLECT_STRUCT_DETAIL_MEMBER_NAME_TEST, \
BOOST_PP_EMPTY) \
throw std::runtime_error("could not find " \
BOOST_PP_STRINGIZE(NAME) \
" member"); \
} \
} \
} \
\
constexpr int BOOST_PP_CAT(indexof_, NAME)(const char* const str, \
const std::size_t len) \
{ \
return detail::BOOST_PP_CAT(reflect_, NAME)::find_member(str, len); \
} \
\
template <std::size_t N> \
constexpr int BOOST_PP_CAT(indexof_, NAME)(const char (&str)[N]) \
{ \
return detail::BOOST_PP_CAT(reflect_, NAME)::find_member(&str[0], N); \
}
#define REFLECT_STRUCT_DETAIL_EXTRACT_NAME(pair) \
BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(1, pair))
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME(r, data, n, elem) \
REFLECT_STRUCT_DETAIL_MEMBER_NAME_DETAIL(n, REFLECT_STRUCT_DETAIL_EXTRACT_NAME(elem))
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME_DETAIL(n, name) \
template <> \
struct member_name<n> \
{ \
static constexpr std::size_t value_length = sizeof(name); \
typedef const char value_type[value_length]; \
\
static constexpr const value_type& value() \
{ \
return name; \
} \
};
#define REFLECT_STRUCT_DETAIL_MEMBER_NAME_TEST(z, n, text) \
member_match<n>(str, len) ? n :
It looks scary but its readable if you take the time to pick it apart.
We have to introduce our own macros to give constant-expression access to the member names; most of the ugly comes from processing Boost.Preprocessor lists. Although Fusion does record the names during adaptation as well (see boost::fusion::extension::struct_member_name), they are not marked as constexpr so aren't usable to us, unfortunately.
This gives:
#include <boost/fusion/include/at_c.hpp>
#include <iostream>
#include <string>
struct Data
{
std::string firstMember;
std::string secondMember;
std::string thirdMember;
};
REFLECT_STRUCT(
Data,
(std::string, firstMember)
(std::string, secondMember)
(std::string, thirdMember)
)
// your desired code:
// (note the use of at_c ensures this is evaluated at comple-time)
#define GETMEMBER(data, member) boost::fusion::at_c<indexof_Data(member)>(data)
int main()
{
Data d = { "firstData", "secondData", "thirdData" };
std::cout << boost::fusion::at_c<indexof_Data("firstMember")>(d) << std::endl;
std::cout << GETMEMBER(d, "secondMember") << std::endl;
std::cout << GETMEMBER(d, "thirdMember") << std::endl;
/* causes error: std::cout << GETMEMBER(d, "nonexistent_member") << std::endl; */
}
Which I think is close to what you were after.
But keep in mind this may not all be necessary: Boost.Fusion may already have what you need. It lives in the area between pure compile-time stuff (Boost.MPL) and regular run-time stuff; adapt your struct and you can already do things like iterate over it (boost::fusion::for_each).