2008-10-08 20 views
11

Tôi có một lớp mẫu C++ được khởi tạo với 3 tham số kiểu khác nhau. Có một phương thức mà lớp cần có cho một trong các loại đó và không bao giờ được gọi với hai loại khác.Mã đối tượng có được tạo cho các phương thức lớp mẫu không được sử dụng không?

Mã đối tượng cho phương thức đó sẽ được tạo ba lần (đối với tất cả các loại mà mẫu được khởi tạo) hoặc mã đối tượng chỉ được tạo một lần (đối với loại thực tế được sử dụng)?

Trả lời

20

Chức năng thành viên ảo được khởi tạo khi một mẫu lớp được khởi tạo, nhưng các chức năng thành viên không phải ảo được khởi tạo chỉ khi chúng được gọi.

Điều này được đề cập trong [temp.inst] trong tiêu chuẩn C++ (Trong C++ 11, đây là §14.7.1/10. Trong C++ 14, nó là §14.7.1/11 và trong C++ 17 nó là §17.7.1/9. Trích từ C++ 17 dưới đây)

An thực hiện sẽ không ngầm nhanh chóng một hàm mẫu, một mẫu biến, một mẫu thành viên , một tổ chức phi ảo chức năng thành viên, một lớp thành viên, một thành viên dữ liệu tĩnh của một mẫu lớp, hoặc một sự thay thế của câu lệnh constexpr nếu (9.4.1), trừ khi yêu cầu như vậy được yêu cầu

Cũng lưu ý rằng có thể khởi tạo một mẫu lớp ngay cả khi một số hàm thành viên không thể thực hiện được đối với các tham số mẫu đã cho. Ví dụ:

template <class T> 
class Xyzzy 
{ 
public: 
    void CallFoo() { t.foo(); } // Invoke T::foo() 
    void CallBar() { t.bar(); } // Invoke T::bar() 

private: 
    T t; 
}; 

class FooBar 
{ 
public: 
    void foo() { ... } 
    void bar() { ... } 
}; 

class BarOnly 
{ 
public: 
    void bar() { ... } 
}; 

int main(int argc, const char** argv) 
{ 
    Xyzzy<FooBar> foobar; // Xyzzy<FooBar> is instantiated 
    Xyzzy<BarOnly> baronly; // Xyzzy<BarOnly> is instantiated 

    foobar.CallFoo();   // Calls FooBar::foo() 
    foobar.CallBar();   // Calls FooBar::bar() 

    baronly.CallBar();  // Calls BarOnly::bar() 

    return 0; 
} 

Điều này là hợp lệ, mặc dù Xyzzy :: CallFoo() không thể thực hiện được vì không có điều gì như BarOnly :: foo(). Tính năng này được sử dụng thường xuyên như một công cụ lập trình meta mẫu.

Lưu ý, tuy nhiên, "instantiation" của mẫu không tương quan trực tiếp đến số lượng mã đối tượng được tạo. Điều đó sẽ phụ thuộc vào trình biên dịch/trình liên kết của bạn thực hiện.

+0

Chúng ta cũng nên lưu ý rằng không phải tất cả chức năng đều có thể được khởi tạo và điều này là ok miễn là chúng không được gọi. –

+0

Xong. Tôi nghĩ về điều đó khi ban đầu trả lời, nhưng chỉ là quá lười biếng để viết một lời giải thích đầy đủ. –

+0

Có thể đánh dấu phương thức được khởi tạo nhanh (tức là ngăn không cho nó được tối ưu hóa) mà không làm cho nó trở thành ảo không? Cảm ơn! – Serge

1

Thông thường, có.

Tất cả trình biên dịch thực sự biết là chương trình của bạn có thể tạo ít nhất một phiên bản của mỗi lớp. Nhưng nó không biết bạn sẽ làm gì với những trường hợp đó. Vì vậy, mã sẽ gần như chắc chắn được tạo ra.

Điều đó nói rằng, nếu các phương pháp trong câu hỏi là không ảo, và không bao giờ gọi, mối liên kết thể gỡ bỏ chúng với các tính năng loại bỏ mã chết bình thường của nó. Vì vậy, mã được tạo ra (và biên dịch) sẽ không có trong EXE cuối cùng.

Điều này cũng phụ thuộc phần lớn vào trình biên dịch C++ đang được sử dụng vì chúng không giống nhau.

2

Tôi nghĩ nó phụ thuộc vào trình biên dịch và cài đặt. Ví dụ, tôi tin rằng MSVC6 tạo ra mọi thứ, nhưng VS2005 thì không. Các spec nói trình biên dịch không nên, nhưng trong thế giới thực, nó phụ thuộc vào trình biên dịch thực tế (có nhiều work-arounds trong tăng cho MSVC6, ví dụ). Trình liên kết có thể xóa các hàm không được trả lời nếu/opt: ref được bật (đối với VS, các tùy chọn tương đương tồn tại đối với các trình biên dịch khác).

+2

Tốt cũ MSVC6 và các mẫu, ah những ngày ... kinh dị. – QBziZ

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