2017-10-13 33 views
6

它可以创建一个宏str(a)将使用它的参数(a)和它的字符串化的名称(#a),例如:如何获得可变宏中每个参数的名称?

#include <iostream> 

#define str(a) #a, " ", a 

int main() 
{ 
    int i = 5; 
    float f = 4.5; 
    const char* s = "string"; 

    auto l = [] (const auto&... p) { (std::cout << ... << p) << std::endl; }; 

    l(str(i)); 
    l(str(f)); 
    l(str(s)); 
} 

Example

是否有一个简单的方法来打印变量参数的数量前加上每个参数的名称?即实现从以下PREPEND_EACH_ARG_WITH_HASH_ARG

#include <iostream> 
#include <tuple> 

template <typename ... Ts> 
void print_all(const Ts&... ts) 
{ 
    (std::cout << ... << ts) << std::endl; 
} 

#define PREPEND_EACH_ARG_WITH_HASH_ARG(...) // how to implement '#a, " ", a' here? 
#define PRINT_ALL(...) print_all(PREPEND_EACH_ARG_WITH_HASH_ARG(__VA_ARGS__)) 

int main() 
{ 
    auto a = 10; 
    auto b = 20.1; 
    auto c = "string"; 
    auto d = 'c'; 
    PRINT_ALL(a, b, c, d); 
} 

Example

回答

5

如果你可以使用Boost.Preprocessor,你可以这样做:

#define PROCESS_ONE_ELEMENT(r, unused, idx, elem) \ 
    BOOST_PP_COMMA_IF(idx) BOOST_PP_STRINGIZE(elem) , " " , elem 

#define PRINT_ALL(...) \ 
    print_all(BOOST_PP_SEQ_FOR_EACH_I(PROCESS_ONE_ELEMENT, %%, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))) 

[Live example]

我用%%作为一个placholder “未使用的价值。”

5

Boost.Preprocessor库绝对是一个很好的解决方案。但是,如果你不希望依赖于外部库,你可以像下面这样:

#include <iostream> 

#define str(a) #a, " = ", a 

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1) 
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N 

#define CONCAT_IMPL(x, y) x##y 
#define MACRO_CONCAT(x, y) CONCAT_IMPL(x, y) 

// to verify, run the preprocessor alone (g++ -E): 
#define PREPEND_EACH_ARG_WITH_HASH_ARG_1(a) str(a) 
#define PREPEND_EACH_ARG_WITH_HASH_ARG_2(a, ...) str(a) , " ; " , PREPEND_EACH_ARG_WITH_HASH_ARG_1(__VA_ARGS__) 
#define PREPEND_EACH_ARG_WITH_HASH_ARG_3(a, ...) str(a) , " ; " , PREPEND_EACH_ARG_WITH_HASH_ARG_2(__VA_ARGS__) 
#define PREPEND_EACH_ARG_WITH_HASH_ARG_4(a, ...) str(a) , " ; " , PREPEND_EACH_ARG_WITH_HASH_ARG_3(__VA_ARGS__) 
#define PREPEND_EACH_ARG_WITH_HASH_ARG_5(a, ...) str(a) , " ; " , PREPEND_EACH_ARG_WITH_HASH_ARG_4(__VA_ARGS__) 
#define PREPEND_EACH_ARG_WITH_HASH_ARG(...) MACRO_CONCAT(PREPEND_EACH_ARG_WITH_HASH_ARG_, VA_NUM_ARGS(__VA_ARGS__)) (__VA_ARGS__) 
#define PRINT_ALL(...) print_all(PREPEND_EACH_ARG_WITH_HASH_ARG(__VA_ARGS__)) 

template<typename T> 
void print_impl(const T& t) 
{ 
    std::cout << t; 
} 

template<typename T, typename... Ts> 
void print_impl(const T& t, const Ts&... ts) 
{ 
    std::cout << t; 
    print_impl(ts...); 
} 


template <typename ... Ts> 
void print_all(const Ts&... ts) 
{ 
    print_impl(ts...); 
    std::cout << std::endl; 
} 

int main() 
{ 
    auto a = 10; 
    auto b = 20.1; 
    auto c = "string"; 
    auto d = 'c'; 
    PRINT_ALL(a, b, c, d); 
} 

这里的想法是计算使用VA_NUM_ARGS参数的数量和使用的结果调用正确的PREPEND_EACH_ARG_WITH_HASH_ARG_#宏,对于__VA_ARGS__中的每个参数,它将“递归地”调用下一个PREPEND_EACH_ARG_WITH_HASH_ARG_#

它的一个小缺点是它的参数数量有限,但另一方面这很容易扩展。

+0

IOW,自己重新实现Boost.Preprocessor的那一点:-) – Angew

+0

@Angew是或多或少:)我不确定Boost库究竟是如何实现的(它可能比我的例子更智能一些)。我通常喜欢独立于第三方库,所以我认为这个解决方案值得一提。 – Banan

+0

@Banan,感谢您的解释,但是接受提升为答案的参考,因为它更“简单”:) –

相关问题