2015-10-17 15 views
12

Mã sau đây biên dịch với Cộng đồng VS15 và in ra "Xin chào".Hành vi không mong muốn với bí danh loại mẫu trong VS2015

#include <functional> 
#include <iostream> 

template<typename T> 
using void_template_alias_t = void; 

template<typename T> 
using Func = std::function<void(T)>; 

template<typename T> 
using FuncVoid = Func<void_template_alias_t<T>>; 

int main() 
{ 
    FuncVoid<void> hello = [] { std::cout << "Hello\n"; }; 
    hello(); 
} 

Tôi nghĩ điều này không được phép biên dịch.

Tôi đang chơi xung quanh, mã phức tạp hơn một chút. Tôi ngây thơ mong đợi điều này để làm việc, nhưng đột nhiên nhận ra rằng mã này không nên biên dịch bởi vì bạn không thể thực hiện một Func<void> (hoặc tôi là sai với điều này?).

  • Tôi có tìm thấy giải pháp thay thế không?
  • Đây có phải là hành vi mới từ tiêu chuẩn C++ 14 không?
  • Hay đơn giản là lỗi trình biên dịch?

Chỉnh sửa: Phiên bản đơn giản hơn sau đây không biên dịch.

#include <functional> 
#include <iostream> 

template<typename T> 
using Func = std::function<void(T)>; 

int main() 
{ 
    Func<void> hello = [] { std::cout << "Hello\n"; }; 
    hello(); 
} 
  • Vậy tại sao là mã trên biên dịch và làm việc như tôi lần đầu tiên dự kiến?
  • Đây có phải là cách triển khai chính xác, nếu không, nó sẽ như thế nào?
+0

Có một thế giới khác biệt giữa 'foo (void)' và 'sử dụng X = void; foo (X); '. Tôi sẽ ngạc nhiên nếu các trình biên dịch khác chấp nhận điều này. –

+0

Ồ, tôi đã quá chắc chắn. Tiêu chuẩn nói rằng "Danh sách tham số' (void) 'tương đương với danh sách tham số trống.", Nhưng không xác định rằng '(void)' là văn bản theo nghĩa đen. Và không có sản xuất ngữ pháp đặc biệt nào cho nó, và cả g ++ và Visual C++ biên dịch 'void foo (X)' trong đó 'X' là tên của' void', và chúng biên dịch cuộc gọi 'foo()'. –

+0

Có lẽ tôi nên chú ý rõ ràng hơn, rằng cách diễn giải trong đó '(void)' dùng để chỉ một hàm mà * type * của đối số đơn có hiệu lực 'void', và sau đó biểu thị một hàm không có đối số, không hoạt động tốt với mã mẫu gọi hàm với một đối số, nghĩa là nó không thực tế. Tuy nhiên, cả MSVC và MinGW g ++ đều chấp nhận 'foo (My_void)' không có khuôn mẫu và gọi 'foo()'. :( –

Trả lời

5

Hoặc đơn giản là lỗi trình biên dịch?

Điều đó. Như đã đề cập bởi @TC, CWG #577 là có liên quan:

[...] có được một số mối quan tâm thể hiện qua việc điều trị các chức năng mẫu và thành viên chức năng của lớp mẫu nếu ++ quy tắc C đã được thay đổi: cho một tham số mẫu T, một chức năng có tham số loại T trở thành chức năng không tham số nếu nó được khởi tạo với T = void?

Đây là một khiếu nại chính đáng, nhưng không may cho bạn, chức năng thành viên/chức năng mẫu thành viên và loại-id s đã bị ảnh hưởng không kém bởi độ phân giải:

Một danh sách tham số bao gồm một tham số không tên duy nhất của loại không phụ thuộc void tương đương với danh sách tham số trống.

do đó cả hai đoạn mã của bạn đều không đúng định dạng, vì loại thông số thực sự phụ thuộc.


Có một thực hiện đúng, nếu không, làm thế nào nó sẽ trông như thế nào?

Không có triển khai chính xác.Nếu bạn cần một kiểu hàm với một danh sách tham số rỗng, bạn sẽ phải chỉ rõ rằng nó độc lập với các tham số mẫu.

Vậy tại sao mã ở trên biên dịch và hoạt động như tôi mong đợi lần đầu tiên?

đoán tốt nhất của tôi: VC++ thực hiện việc thay thế void_template_alias_t<T>sau đảm bảo rằng các loại tham số không phải là một phụ thuộc gõ "cv void", nhưng trước khi thực hiện "void -> chuyển đổi danh sách trống". Tuy nhiên, thường khó hiểu được cách VC++ (hoặc bất kỳ trình biên dịch nào, cho vấn đề đó) suy nghĩ nội bộ.

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