将多个参数作为单个宏参数传递

Passing multiple parameters as a single macro argumment

本文关键字:单个宏 参数传递 参数      更新时间:2023-10-16

问题

C预处理器有一个#,它可以将后面写的任何表达式转换为原始字符串。例如:

#define make_string(x) #x
int a , b;
const char my_string[] = make_string( a + b ); //my_string holds "a + b"

有什么方法可以执行反向过程吗
我的意思是,获取一个原始字符串并将其转换为一个安全的令牌。例如(~#是执行此操作的理论预处理器运算符):

#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)

某些上下文(或者">我陷入XY问题?")

我正在编写一个模板元编程库,该库主要基于定义元函数并专门化它们以获得不同的行为(如函数重载)
例如:

//Metafunction declaration:
template<typename T , typename U>
struct better_type;

//Metafunction specialization (overload)
template<>
struct better_type<char,unsigned char>
{
using result = char;
};

该库假定元函数是任何具有result公共别名的模板。因此,用户必须执行常见的typename function</*function argumments*/>::result才能获得函数的结果。

为了避免这种情况,我利用了C++11模板别名,只将函数定义为两部分:

  • 函数实现:实现函数的上述形式的元函数。

    template<typename T>
    struct function_impl;
    

    为了实现(重载)他自己版本的功能,用户专门使用这个模板:

    template<>
    struct function_impl<bool>
    {
    using result = /* something */;
    };
    
  • 函数声明:定义用户的函数接口。它只是真正的元函数的别名。

    template<typename T>
    using function = typename function_impl<T>::result;
    

所以函数声明总是一对声明:函数实现和用户界面别名。

现在,我的目标是使用CPP,在一些通用whay中自动进行声明。类似于:

#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

可以用作:

define_function( typename T , my_function , T );

并生成以下代码而没有任何问题:

template< typename T >
struct mi_function_impl;
template< typename T >
using mi_function = typename my_function_impl< T >::type;

但考虑一下其他用法示例:

define_function( typename T , typename U , mi_binary_function , T , U );

当然,typename T , typename U是第一个宏论证,T , U是第二个宏论证。但这是行不通的,因为它们被视为五种不同的宏观论点
这就是我考虑生成令牌的原因,因为有了这个功能,宏可以重新发送为:

#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

并且多个参数将作为生成预期结果的唯一原始字符串传递:

define_function( "typename T , typename U" , mi_binary_function , "T , U" );

X/Y问题的解决方案是使用括号而不是引号:

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;

可以实现为:

#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

但我们也可以自动生成参数名称(无论如何,您都可以在专业化中为它们提供新名称):

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;

可以实现为:

#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)