metalang99: Don't understand how to recurse

I have read the tutorial and write the code according to example but it doesn’t work. I took several hours to try different patterns with v() or without v() but still don’t figure out how to use it. So I came here to find some help, here is the code.

#define _GetUnderlyingType(LayerNumber,CurrentType)															\
	std::enable_if_t<_IsEligibleType<CurrentType,LayerNumber,_default_index>::value,									\
	typename _IsEligibleType<CurrentType,LayerNumber,_default_index>::underlying_type>													

#define _ConstructGetUnderlyingType(TotalLayer,StartLayer,T) ML99_natMatchWithArgs(TotalLayer, v(_ConstructGetUnderlyingType_),StartLayer,T)
#define _ConstructGetUnderlyingType_Z_IMPL(StartLayer,T) v(T)
#define _ConstructGetUnderlyingType_S_IMPL(TotalLayer,StartLayer,T)												\
	_GetUnderlyingType(StartLayer-TotalLayer+2,_ConstructGetUnderlyingType(v(TotalLayer),StartLayer,T))												

	ML99_EVAL(_ConstructGetUnderlyingType(v(1), v(1), v(T)));

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 18 (9 by maintainers)

Most upvoted comments

With your patience and help I finally finished my own project, thank you very much.

By the way, there’s a more neat way to do the same:

#define _PARAM_T typename
#define _PARAM_V auto

#define _ConstructTemplateParameters(...)                                                          \
    ML99_LIST_EVAL_COMMA_SEP(ML99_listMapI(v(_GenTemplateParam), ML99_list(v(__VA_ARGS__))))

#define _GenTemplateParam_IMPL(x, i) v(_PARAM_##x x##i)
#define _GenTemplateParam_ARITY      2

_ConstructTemplateParameters(T, V, T, V)

Output:

typename T0 , auto V1 , typename T2 , auto V3

We could do the trick with some variadics metaprogramming:

#define _ConstructTemplateParameters_S_IMPL(Total, Current, ...)                                   \
    ML99_TERMS(                                                                                    \
        _GetLongName(v(Current), ML99_variadicsGet(0)(v(__VA_ARGS__))),                            \
        ML99_IF(ML99_VARIADICS_IS_SINGLE(__VA_ARGS__), v(), v(, )),                                \
        _ConstructTemplateParameters(                                                              \
            v(Total),                                                                              \
            ML99_inc(v(Current)),                                                                  \
            ML99_variadicsTail(v(__VA_ARGS__))))

This is a fully C99-compliant (C++11) way to accomplish your job.

Oh, It’s my fault, forget it.😂 Thank you for you patience.

On my computer, it just fails:

test.c:17:1: error: macro "_GetUnderlyingType_IMPL" passed 7 arguments, but takes just 2
   17 | ML99_EVAL(_ConstructGetUnderlyingType(v(2), v(1), v(T)));
      | ^~~~~~~~~~~~~~~~~~~~~~~

This is because _GetUnderlyingType reduces to commas, which are treated as macro arguments. To fix it, you can wrap the call using ML99_tuple and then ML99_UNTUPLE them:

#define _GetUnderlyingType_IMPL(LayerNumber, CurrentType)                                          \
    v(std::enable_if_t<                                                                            \
        _IsEligibleType<ML99_UNTUPLE(CurrentType), LayerNumber, _default_index>::value,            \
        typename _IsEligibleType<ML99_UNTUPLE(CurrentType), LayerNumber, _default_index>::         \
            underlying_type>)

#define _ConstructGetUnderlyingType(TotalLayer, StartLayer, T)                                     \
    ML99_natMatchWithArgs(TotalLayer, v(_ConstructGetUnderlyingType_), StartLayer, T)
#define _ConstructGetUnderlyingType_Z_IMPL(StartLayer, T) v(T)
#define _ConstructGetUnderlyingType_S_IMPL(TotalLayer, StartLayer, T)                              \
    ML99_call(                                                                                     \
        _GetUnderlyingType,                                                                        \
        v(StartLayer - TotalLayer + 2),                                                            \
        ML99_tuple(_ConstructGetUnderlyingType(v(TotalLayer), v(StartLayer), v(T))))

ML99_EVAL(_ConstructGetUnderlyingType(v(2), v(1), v(T)));

The expansion output:

std::enable_if_t< _IsEligibleType<std::enable_if_t< _IsEligibleType<T, 1 - 0 + 2, _default_index>::value, typename _IsEligibleType<T, 1 - 0 + 2, _default_index>:: underlying_type>, 1 - 1 + 2, _default_index>::value, typename _IsEligibleType<std::enable_if_t< _IsEligibleType<T, 1 - 0 + 2, _default_index>::value, typename _IsEligibleType<T, 1 - 0 + 2, _default_index>:: underlying_type>, 1 - 1 + 2, _default_index>:: underlying_type>;

Hope this helps.

Try this:

#define _GetUnderlyingType_IMPL(LayerNumber, CurrentType)                                          \
    v(std::enable_if_t<                                                                            \
        _IsEligibleType<CurrentType, LayerNumber, _default_index>::value,                          \
        typename _IsEligibleType<CurrentType, LayerNumber, _default_index>::underlying_type>)

#define _ConstructGetUnderlyingType(TotalLayer, StartLayer, T)                                     \
    ML99_natMatchWithArgs(TotalLayer, v(_ConstructGetUnderlyingType_), StartLayer, T)
#define _ConstructGetUnderlyingType_Z_IMPL(StartLayer, T) v(T)
#define _ConstructGetUnderlyingType_S_IMPL(TotalLayer, StartLayer, T)                              \
    ML99_call(                                                                                     \
        _GetUnderlyingType,                                                                        \
        v(StartLayer - TotalLayer + 2),                                                            \
        _ConstructGetUnderlyingType(v(TotalLayer), v(StartLayer), v(T)))

ML99_EVAL(_ConstructGetUnderlyingType(v(1), v(1), v(T)));

The above code gives the following output:

std::enable_if_t< _IsEligibleType<T, 1 - 0 + 2, _default_index>::value, typename _IsEligibleType<T, 1 - 0 + 2, _default_index>::underlying_type>;

The thing is that an invocation of _ConstructGetUnderlyingType is a Metalang99 term, but in your example, you feed it to _GetUnderlyingType, which is not evaluated by Metalang99 further. In my example, I define _GetUnderlyingType as a ML99-compliant metafunction so its arguments are fully evaluated.