2015-03-29 13 views
7

Làm cách nào để tạo macro có số lượng đối số thay đổi và in ra bằng lệnh std :: cout? Xin lỗi nếu đây là một câu hỏi noob, không thể tìm thấy bất cứ điều gì làm rõ các macro variadic sau khi tìm kiếm câu trả lời.Làm thế nào để thực hiện một macro variadic cho std :: cout?

Khái niệm Ví dụ:

#include <iostream> 
#define LOG(...) std::cout << ... << ... << std::endl 
int main() { 
    LOG("example","output","filler","text"); 
    return 0; 
} 

sẽ ra:

exampleoutputfillertext 
+1

Tại sao? Tại sao? Tại sao? chỉ cần viết mã –

Trả lời

6

Khi sử dụng macro variadic bạn cần __VA_ARGS__ để mở rộng tất cả các đối số. Tuy nhiên, vấn đề là các đối số đó được phân cách bằng dấu phẩy. Giả sử nó chỉ tách các đối số cho một cuộc gọi hàm, nhưng vì các macro chỉ hoạt động với văn bản, bạn thực sự có thể sử dụng __VA_ARGS__ trong các ngữ cảnh khác, trong đó danh sách được phân cách bằng dấu phẩy có ý nghĩa.

Bí quyết bạn có thể sử dụng là xác định toán tử dấu phẩy của riêng mình cho std::ostream (loại std::cout). Ví dụ:

#include<iostream> 
#define LOG(...) std::cout , __VA_ARGS__ , std::endl 

template <typename T> 
std::ostream& operator,(std::ostream& out, const T& t) { 
    out << t; 
    return out; 
} 

//overloaded version to handle all those special std::endl and others... 
std::ostream& operator,(std::ostream& out, std::ostream&(*f)(std::ostream&)) { 
    out << f; 
    return out; 
} 

int main() { 
    LOG("example","output","filler","text"); 
    return 0; 
} 

Bây giờ, gọi LOG sẽ mở rộng tới:

std::cout , "example" , "output" , "filler" , "text" , std::endl; 

và dấu phẩy sẽ gọi các nhà khai thác dấu phẩy quá tải.

Nếu bạn không muốn quá tải operator, gây ô nhiễm tất cả std::ostream -s, bạn có thể đóng gói std::cout bằng lớp ghi nhật ký đặc biệt của riêng bạn.

+0

không phải là '__VA_ARGS__' gcc cụ thể? – vsoftco

+3

Với kiến ​​thức của tôi '__VA_ARGS__' được hỗ trợ trong mọi trình biên dịch C/C++ hỗ trợ các macro Vĩ mô ngay từ đầu. Macro biến thể là tiêu chuẩn trong C và C++ 11 nhưng không phải là C++. – CygnusX1

+0

cảm ơn, không biết họ làm cho nó thành C++ 11. câu trả lời tới điểm, upvoted – vsoftco

1

Không chắc chắn có cách nào để xác định macro Vĩ mô trong C++ (ít nhất, không phải là cách di động). Tại sao bạn không sử dụng phương pháp tiếp cận mẫu Denisdic? Một cái gì đó như

#include <iostream> 

void LOG() {} 

template<typename Head, typename... Args> 
void LOG(const Head& head, const Args&... args) 
{ 
    std::cout << head << " "; 
    LOG(args...); 
} 

int main() 
{ 
    LOG("This", "is" , "the", 3, "rd test"); 
} 
+0

Bạn cần một điều kiện chấm dứt để ngăn chặn mẫu đó được đệ quy vô hạn. – Peter

+0

@Peter đó là những gì 'void LOG()' không – vsoftco

13

Bạn không cần macro tiền xử lý để thực hiện việc này. Bạn có thể viết nó trong bình thường C++:

#include <iostream> 
#include <utility> 

void log(){} 

template<typename First, typename ...Rest> 
void log(First && first, Rest && ...rest) 
{ 
    std::cout << std::forward<First>(first); 
    log(std::forward<Rest>(rest)...); 
} 

int main() 
{ 
    log("Hello", "brave","new","world!\n"); 
    log("1", 2,std::string("3"),4.0,'\n'); 
} 

đầu ra:

Hellobravenewworld! 
1234 

Bạn nên nghiên cứu variadic templatesparameter packs hơn là macro variadic, đó là hiếm khi hữu ích trong việc hiện đại, C++.

(gcc 4.9.2 -std = C++ 11)

+0

Được rồi! Cảm ơn vì lời khuyên. Mã nó khá rực rỡ :-) – BlurryZombie

+0

@BlurryZombie Bạn được chào đón.Mã này hoàn toàn phổ biến. Bạn chỉ cần tìm hiểu về các tính năng tôi đã đề cập. –

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