2017-10-13 14 views
6

Có thể tạo một macro str(a) rằng sẽ sử dụng đối số của nó (a) và tên chuyển đổi thành chuỗi của nó (#a), ví dụ:Làm thế nào để có được tên cho mỗi đối số trong các macro variadic?

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

Có cách đơn giản để in biến số số đối số được thêm vào trước với tên của mỗi đối số không? tức là thực hiện PREPEND_EACH_ARG_WITH_HASH_ARG từ các mục sau:

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

Trả lời

5

Nếu bạn có thể sử dụng Boost.Preprocessor, bạn có thể làm điều này:

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

tôi sử dụng %% như một placholder cho "giá trị sử dụng."

5

Thư viện Boost.Preprocessor chắc chắn là một giải pháp tuyệt vời. Tuy nhiên, nếu bạn không muốn trở thành phụ thuộc vào thư viện bên ngoài, bạn có thể giống như sau:

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

Ở đây, ý tưởng là để đếm số lượng các đối số sử dụng VA_NUM_ARGS và sử dụng kết quả đó để gọi chính xác PREPEND_EACH_ARG_WITH_HASH_ARG_# macro, sẽ "đệ quy" gọi PREPEND_EACH_ARG_WITH_HASH_ARG_# tiếp theo cho mỗi đối số trong __VA_ARGS__.

Hạn chế nhỏ là nó bị giới hạn về số lượng đối số có thể mất, nhưng mặt khác, điều này có thể dễ dàng mở rộng.

+0

IOW, triển khai lại bit đó Boost.Preprocessor chính mình :-) – Angew

+0

@Angew Có nhiều hơn hoặc ít hơn :) Tôi không chắc chính xác thư viện Boost được triển khai như thế nào (có lẽ thông minh hơn một chút so với ví dụ của tôi). Tôi thường thích được độc lập với các thư viện của bên thứ ba, vì vậy tôi nghĩ rằng giải pháp đáng nói đến. – Banan

+0

@Banan, cảm ơn vì những lời giải thích, tuy nhiên chấp nhận tham chiếu để tăng thêm câu trả lời vì nó là "cách đơn giản hơn" :) –

Các vấn đề liên quan