12

hiểu biết của tôi về C++ ngầm constructor sao chép tương tự nhưlý do đằng sau C++ ngầm sao chép và di chuyển constructor?

T(T const& x) : 
    base1(x), base2(x) ... , 
    var1(x.var1), var2(x.var2)... 
{} 

Move constructor, sao chép & phân di chuyển cũng theo mô hình tương tự.

Tại sao nó không được xác định tương tự như sau?

T(T const& x) : 
    base1(static_cast<base1 const&>(x)), 
    base2(static_cast<base2 const&>(x)) ... , 
    var1(x.var1), var2(x.var2)... 
{} 

Ví dụ

Tôi đã có một lớp mà có sao chép/di chuyển hành constructor/chuyển nhượng ngầm, cũng như một số nhà xây dựng chuyển đổi. Tôi đã được giao công việc cho một số lớp thực hiện.

class common_work //common implementation of many work like classes 
{ 
    common_work(common_work const&) = default; 
    common_work(common_work&&) = default;// ... implicit constructors work for me. 
    //a forwarding constructor which can take many work like objects 
    template<class T, enable_if<work_like<T> > > 
    common_work(T&& x) { ... } 
}; 
class work1 //one of the implementation 
{ 
    work1(work1 const&) = default; 
    work1(work1&&) = default; ... 
    common_work impl_; 
}; 

Đây là tốt, như work1 sao chép/di chuyển nhà xây dựng đã kêu gọi constructor sao chép/di chuyển cho common_work, và chuyển tiếp constructor được sử dụng bởi nhà thầu khác [không được hiển thị trong code] mà chuyển đổi từ một loại work.

Sau đó, tôi nghĩ rằng để kế thừa work1 từ common_work cho EBO và các lý do khác. Vì vậy, các lớp mới work1 trông giống như

class work1 : private common_work 
{ 
    work1(work1 const&) = default; 
    work1(work1&&) = default; ... 
}; 

Nhưng, work1 là một lớp work_like, đột nhiên các nhà xây dựng chuyển tiếp đã nhận được một trận đấu tốt hơn, như các nhà xây dựng sao chép/di chuyển cho common_work đòi hỏi một static_cast từ nguồn gốc đến cơ sở.

LƯU Ý:

  • Có một loại tương tự của các ví dụ được đưa ra bởi Scott Meyers, nơi xây dựng bản sao gây nên chuyển tiếp constructor như constructor sao chép đòi hỏi một bổ sung const, trong khi chuyển tiếp constructor đòi hỏi gì. Nhưng tôi nghĩ, vấn đề đó phát sinh do thiết kế lớp sai, trong khi vấn đề ở đây là do đối số được chuyển đến lớp cơ sở trong khi sao chép/di chuyển ngầm không chính xác.
  • Tôi không thể viết một công cụ chuyển tiếp/gán nhiệm vụ chuyển tiếp phổ biến và xóa các hàm ẩn, vì các hàm bị xóa cũng tham gia vào quá trình phân giải quá tải và gây ra lỗi nếu khớp chính xác.
  • Giải pháp hiện tại tôi có là để làm cho common_work làm CRTP, tức là loại lớp dẫn xuất được chuyển làm đối số mẫu và trong bộ xây dựng chuyển tiếp lọc nó ra là enable_if<and_<work_like<T>,not_<is_same<T,Derived> > > >. Nếu không, tôi phải viết thủ công hàm sao chép/di chuyển/gán cho work1static_cast đến các lớp cơ sở một cách rõ ràng, đó là lỗi, dễ bị lỗi và bảo trì.
+0

Có lẽ bạn có thể giải quyết vấn đề này bằng cách tăng cường ràng buộc SFINAE để từ chối 'T' có nguồn gốc từ 'common_work'? –

+0

Đó là những gì tôi làm hiện nay. Nhìn vào điểm thứ ba trên phần LƯU Ý. Mặc dù, nó không được là 'is_same ', thay vì 'is_same , có nguồn gốc>' – abir

+0

OK, xin lỗi. Tôi không đọc ghi chú cuối cùng :) –

Trả lời

1

Vấn đề này đã được thảo luận trên trang trình gỡ lỗi MSVC++ cách đây vài năm (vì vậy nếu nó chưa được khắc phục, đó là sự cố đã biết trên MSVC++). Tiêu chuẩn nói

  • ... cơ sở hoặc thành viên được khởi tạo trực tiếp với cơ sở hoặc thành viên tương ứng của x.

Tôi đã thử nghiệm các trình biên dịch khác nhau khi tôi đọc báo cáo lỗi và tất cả đều được "đưa vào kỳ diệu". Tiêu chuẩn dường như im lặng trên rất chi tiết (cũng về danh mục giá trị và c/v vòng loại) và chỉ nói "với cơ sở tương ứng ... của x", mà IMO có ý nghĩa hơn nhiều nếu bạn mang nó đến trung bình "với không x, nhưng với cơ sở tương ứng ... của x" thay vì bạn vượt qua nó đối tượng hoàn chỉnh (tôi thậm chí sẽ đi xa như nói rằng nó có thể chỉ có ý nghĩa theo cách đó).

+0

Lưu ý rằng các hàm thành viên đặc biệt mặc định rõ ràng chưa được triển khai trong MSVC (mặc dù họ cho biết họ sẽ sớm nhận được chúng trong RTM 2013). –

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