2009-01-09 30 views
13

Trong ANSI C++, làm thế nào tôi có thể gán dòng cout cho một tên biến? Những gì tôi muốn làm là, nếu người dùng đã chỉ định một tên tập tin đầu ra, tôi gửi đầu ra ở đó, nếu không, gửi nó vào màn hình. Vì vậy, một cái gì đó như:Gán cout cho một tên biến

ofstream outFile; 
if (outFileRequested) 
    outFile.open("foo.txt", ios::out); 
else 
    outFile = cout; // Will not compile because outFile does not have an 
        // assignment operator 

outFile << "whatever" << endl; 

tôi đã cố gắng làm điều này như một chức năng Macro cũng như:

#define OUTPUT outFileRequested?outFile:cout 

OUTPUT << "whatever" << endl; 

Nhưng điều đó đã cho tôi một lỗi biên dịch là tốt.

Tôi cho rằng tôi có thể sử dụng khối IF-THEN cho mọi đầu ra, nhưng tôi muốn tránh điều đó nếu có thể. Bất kỳ ý tưởng?

Trả lời

34

Sử dụng một tài liệu tham khảo. Lưu ý rằng tham chiếu phải thuộc loại std::ostream, không phải std::ofstream, vì std::cout là một số std::ostream, vì vậy bạn phải sử dụng mẫu số chung ít nhất.

std::ofstream realOutFile; 

if(outFileRequested) 
    realOutFile.open("foo.txt", std::ios::out); 

std::ostream & outFile = (outFileRequested ? realOutFile : std::cout); 
+1

Đó là giải pháp rất thanh lịch. Cảm ơn! – user12576

0

Tôi nghĩ rằng Adam đi đúng hướng nhưng tôi không nghĩ rằng bạn có thể gán tài liệu tham khảo - bạn cần phải sử dụng một con trỏ thay vì:

std::ofstream realOutFile; 
std::ostream * poutFile; 

if(outFileRequested) 
{ 
    realOutFile.open("foo.txt", std::ios::out); 
    poutFile = &realOutFile; 
} 
else 
    poutFile = &std::cout; 

sau đó bạn có thể định nghĩa một tài liệu tham khảo để có giá trị của con trỏ, nhưng nó sẽ không được toàn cầu

std::ostream & outFile = *poutFile; 
+0

Nên luôn luôn thích sử dụng tài liệu tham khảo hơn con trỏ. Và nó có thể được thực hiện với các tham chiếu. Xem mã cố định ở trên. –

+1

Chắc chắn, bạn không thể sử dụng biến toàn cục với tham chiếu b/c bạn sẽ không thể khởi tạo đúng giá trị. – KenE

0

Tôi không chắc chắn rằng bạn có thể gán cout cho một loại biến dòng. cout là một đối tượng của loại ostream (trong khi cin là loại istream) và tôi không chắc chắn rằng một trong những kế thừa từ khác. Vì vậy, có thể một cái gì đó kiểm tra để xem nếu một tập tin đã được đưa ra/tồn tại và tạo ra các loại dòng thích hợp sẽ là một cách tiếp cận tốt hơn.

1

Sau track Adam Rosenfield 's, nhưng sửa chữa các vấn đề tham khảo khởi với những hoạt động ternary và dấu phẩy:

bool outFileRequested = false; 

std::ofstream realOutFile; 
std::ostream & outFile = outFileRequested 
    ? realOutFile.open("foo.txt", std::ios::out), realOutFile 
    : std::cout; 

outFile << "some witty remark"; 

(Tested trong VS)

8

tôi giả sử chương trình của bạn hoạt động như công cụ unix tiêu chuẩn , khi không đưa ra một tập tin sẽ ghi vào đầu ra tiêu chuẩn, và khi được đưa ra một tập tin sẽ ghi vào tập tin đó. Bạn có thể chuyển hướng cout để viết vào bộ đệm luồng khác. Miễn là chuyển hướng của bạn còn sống, mọi thứ được viết cho cout được viết rõ ràng đến đích bạn đã chỉ định. Khi các đối tượng chuyển hướng đi ra khỏi phạm vi, dòng ban đầu được đưa ra và sẽ ghi vào màn hình một lần nữa:

struct CoutRedirect { 
    std::streambuf * old; 
    CoutRedirect():old(0) { 
     // empty 
    } 

    ~CoutRedirect() { 
     if(old != 0) { 
      std::cout.rdbuf(old); 
     } 
    } 

    void redirect(std::streambuf * to) { 
     old = std::cout.rdbuf(to); 
    } 
} 

int main() { 
    std::filebuf file; 
    CoutRedirect pipe; 
    if(outFileRequested) { 
     file.open("foo.txt", std::ios_base::out); 
     pipe.redirect(&file); 
    } 
} 

Bây giờ, cout được chuyển đến tập tin miễn là ống đang sống trong chính. Bạn có thể làm cho nó nhiều hơn "sản xuất đã sẵn sàng" bằng cách làm cho nó không thể sao chép được, bởi vì nó không sẵn sàng để được sao chép: Nếu bản sao nằm ngoài phạm vi, nó sẽ khôi phục luồng gốc đã có.

+0

Tôi nghĩ rằng cấu trúc này nên là một singleton. –

+2

Hosam, nó cố tình không phải là một singleton, để cho phép tạm thời thay đổi điểm đến của cout, một singleton sẽ thay đổi cout mãi mãi. ngay cả khi bạn không muốn thay đổi nó chỉ tạm thời, nếu bạn có thể làm điều gì đó mà không có một singleton, bạn nên làm điều đó mà không có. Ở đây, tôi nghĩ rằng nó có thể thực hiện rõ ràng mà không cần –

0

Quá trình này mất khoảng hai giờ để nhận. Về cơ bản, tôi có một lớp bên ngoài chạy một bộ thử nghiệm. Tôi gửi trong một đại biểu để chạy các bài kiểm tra, do đó, để có quyền truy cập vào đầu ra tôi cần phải gửi trong một dòng đầu ra.Tôi đoán tôi có thể đã thực hiện một luồng khác nhau cho mỗi thử nghiệm. Dù sao, tôi muốn vượt qua trong dòng chảy để được sử dụng sau này.

// Main code to create Test Suite Object 
ofstream debugFile("debug.txt"); 
TestSuiteObject* myTestSuite = new TestSuiteObject(&debugFile); 

// Test Suite Object 
class TestSuiteObject: public Test::Suite 
{ 
public: 
TestSuiteObject(std::ofstream* debug) : m_debug(*debug) 
{ 
    m_debug << "some witty remark" << std::endl; 
    TEST_ADD(TestSuiteObject::test1); 
    TEST_ADD(TestSuiteObject::test2); 
    TEST_ADD(TestSuiteObject::test3); 

} 

void test1(); 
void test2(); 
void test3(); 

private: 
std::ofstream& m_debug; 
}; 
+0

Bạn có chắc chắn rằng bạn đã đặt nó ở đúng nơi không? Nó dường như không đáp ứng với câu hỏi ... – dmckee

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