2012-06-14 4 views
8

Trong đoạn mã sau, hàm tạo variadic được gọi hai lần. Làm thế nào tôi có thể nhận được constructor sao chép được gọi thay vì phiên bản đối số duy nhất của constructor variadic khi thích hợp?Làm thế nào để có được hàm tạo bản sao được gọi là trên một hàm tạo variadic?

#include <iostream> 

struct Foo 
{ 
    Foo(const Foo &) 
    { 
     std::cout << "copy constructor\n"; 
    } 

    template<typename... Args> 
    Foo(Args&&... args) 
    { 
     std::cout << "variadic constructor\n"; 
    } 

    std::string message; 
}; 

int main() 
{ 
    Foo f1; 
    Foo f2(f1); // this calls the variadic constructor, but I want the copy constructor. 
} 

Trả lời

9

Điều này thực sự không có gì để làm với thực tế rằng các nhà xây dựng là variadic. Lớp sau có mẫu constructor không phải là variadic thể hiện cùng một hành vi:

struct Foo 
{ 
    Foo() { } 

    Foo(const Foo& x) 
    { 
     std::cout << "copy constructor\n"; 
    } 

    template <typename T> 
    Foo(T&& x) 
    { 
     std::cout << "template constructor\n"; 
    } 

}; 

Vấn đề là mẫu hàm tạo là kết hợp tốt hơn. Để gọi hàm tạo bản sao, cần phải chuyển đổi tiêu chuẩn để ràng buộc giá trị không phải là const f1 đến const Foo& (phải thêm tiêu chuẩn const).

Để gọi các mẫu nhà xây dựng, không chuyển đổi được yêu cầu: T có thể được suy luận để Foo&, mà sau khi tham khảo sụp đổ (Foo& && ->Foo&), cung cấp cho các tham số x loại Foo&.

Bạn có thể giải quyết vấn đề này bằng cách cung cấp một hàm tạo bản sao thứ hai có tham số tham chiếu không phải lvalue Foo&.

+1

Có một chút nữa, cụ thể là tham chiếu sụp đổ (gọi là?), Nghĩa là 'T &&&' => 'T &' bởi vì nếu không một giá trị ('f1') không thể liên kết với' T && '. –

4

Chỉ cần cung cấp một quá tải phù hợp chính xác, có nghĩa là mật với một phi constFoo&, ngoài các nhà xây dựng bản sao thông thường. Sau đó, bạn có thể ủy cuộc gọi thông qua một diễn viên rõ ràng:

Foo(Foo& other) : Foo(static_cast<Foo const&>(other)) { }