The C preprocessor has the #
, which converts into a raw string any expression written after it. For example:
#define make_string(x) #x
int a , b;
const char my_string[] = make_string( a + b ); //my_string holds "a + b"
Is there any way to perform the inverse process?
I mean, getting a raw string and convert it into a secuence of tokens. For example ( ~#
is the theorical preprocessor operator which does it):
#define make_tokens(x) ~#x
int a = 0 , b = 1;
int c = make_tokens( "a + b" ); //c holds 1 (The result of a + b addition)
I'm writting a template metaprogramming library which is heavily based on definning metafunctions and specializing them to get different behaviour (Like function overloading).
For example:
//Metafunction declaration:
template<typename T , typename U>
struct better_type;
//Metafunction specialization (overload)
template<>
struct better_type<char,unsigned char>
{
using result = char;
};
The library assumes that a metafunction is any template with a result
public alias. So the user has to do the common typename function</*function argumments*/>::result
to get the result of the function.
To avoid that, I take advantage of C++11 template aliases and just define functions in two parts:
Function implementation : A metafunction of the above form which implements the functionality.
template<typename T> struct function_impl;
To implement (overload) his own version of the function, the user specializes this template:
template<> struct function_impl<bool> { using result = /* something */; };
Function declaration : This defines the function interface for the user. Its just an alias of the real metafunction.
template<typename T> using function = typename function_impl<T>::result;
So function declarations are always a pair of declarations: The function implementation and the user interface alias.
Now my goal is to automatice that declarations in some generic whay, using the CPP. Something like:
#define define_function( template_args , function_name , function_args ) \
template< template_args > \
struct function_name##_impl; \
\
template< template_args > \
using function_name = typename function_name##_impl< function_args >::type
That could be used as:
define_function( typename T , my_function , T );
And produces the following code without any problem:
template< typename T >
struct mi_function_impl;
template< typename T >
using mi_function = typename my_function_impl< T >::type;
But consider other usage example:
define_function( typename T , typename U , mi_binary_function , T , U );
Of course typename T , typename U
are intended to be the first macro argumment, and T , U
the second one. But this cannot work because they are viewed as five different macro argumments.
Thats why I was thinking about token generation, because with that feature the macro could be rewitten as:
#define define_function( template_args , function_name , function_args ) \
template< make_tokens(template_args) > \
struct function_name##_impl; \
\
template< template_args > \
using function_name = typename function_name##_impl< make_tokens(function_args) >::type
and multiple parameters would be passed as an unique raw string generating the expected result:
define_function( "typename T , typename U" , mi_binary_function , "T , U" );
A solution to the X/Y problem is to use parentheses instead of quotation marks:
define_function( (typename T, typename U) , mi_binary_function , (T, U) );
// yields:
template< typename T, typename U > struct mi_binary_function_impl; template< typename T, typename U > using mi_binary_function = typename mi_binary_function_impl < T, U >::type;
can be implemented as:
#define strip_parens(...) __VA_ARGS__
#define define_function( template_args , function_name , function_args ) \
template< strip_parens template_args > \
struct function_name##_impl; \
\
template< strip_parens template_args > \
using function_name = typename function_name##_impl \
< strip_parens function_args >::type // end
But we can also generate the parameter names automatically (you give them new names in specializations anyway):
define_function(foo, (class, int, typename));
// yields:
template< class T0, int T1, typename T2 > struct foo_impl; template< class T0, int T1, typename T2 > using foo = typename foo_impl < T0, T1, T2 > :: result;
can be implemented as:
#define gen_single_param_name(number_plus_2) \
BOOST_PP_CAT(T, BOOST_PP_DEC(BOOST_PP_DEC(number_plus_2))) // end
#define gen_single_param(s, data, elem) elem gen_single_param_name(s)
#define gen_params_from_seq(seq) BOOST_PP_SEQ_TRANSFORM(gen_single_param, _, seq)
#define gen_single_arg(s, data, elem) gen_single_param_name(s)
#define gen_args_from_seq(seq) BOOST_PP_SEQ_TRANSFORM(gen_single_arg, _, seq)
#define define_function_impl(name, param_seq, arg_seq) \
template< BOOST_PP_SEQ_ENUM(param_seq) > \
struct name ## _impl; \
\
template< BOOST_PP_SEQ_ENUM(param_seq) > \
using name = typename name ## _impl \
< BOOST_PP_SEQ_ENUM(arg_seq) > :: result // end
#define define_function_seq(name, param_seq) \
define_function_impl(name, gen_params_from_seq(param_seq), \
gen_args_from_seq(param_seq)) // end
#define define_function(name, param_list) \
define_function_seq(name, BOOST_PP_VARIADIC_TO_SEQ param_list)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.