簡體   English   中英

將多個參數作為單個宏規范傳遞

[英]Passing multiple parameters as a single macro argumment

這個問題

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是第一個宏argumment, 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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM