2016-06-30 32 views
7

Tôi có một số mã C++ 11 không thể biên dịch trên Visual Studio 2015 (Cập nhật 2), nhưng biên dịch mà không có lỗi trên cả Clang và GCC. Vì vậy, tôi nghi ngờ một lỗi trình biên dịch trong Visual Studio, nhưng có lẽ mã của tôi là bằng cách nào đó bị hình thành.Lỗi C1001 trên Visual Studio 2015 với tiêu chuẩn :: enable_if

Lớp thực của tôi BaseUnit là lớp trình bao bọc mẫu trên giá trị double, chú ý đến kích thước vật lý của đại lượng (được biểu thị bằng đơn vị SI m, kg, s, K). Ví dụ, phép nhân của một Speed ​​với một cá thể mẫu Time sẽ tự động cung cấp một cá thể Distance. Vấn đề xảy ra với việc thực hiện phép nhân với một vô hướng. Tôi đã đơn giản hóa lớp học nhiều nhất có thể để hiển thị vấn đề.

#include <type_traits> 

template<int M> 
class BaseUnit 
{ 
public: 
    constexpr explicit BaseUnit(double aValue) : value(aValue) {} 
    template<typename U, typename std::enable_if<std::is_arithmetic<U>::value, int>::type = 0> 
     BaseUnit operator*(U scalar) const { return BaseUnit(value * scalar); } 
    template<typename U, typename std::enable_if<std::is_arithmetic<U>::value, int>::type = 0> 
     friend BaseUnit operator* (U scalar, BaseUnit v) { return BaseUnit(scalar*v.value); } 
protected: 
    double value; 
}; 

int main() 
{ 
    BaseUnit<1> a(100); 
    a = 10 * a; // <-- error C1001 here 
    return 0; 
} 

Khi biên dịch trên Visual Studio, bất kể các tùy chọn dòng lệnh, lỗi nội bộ C1001 xuất hiện:

C:\temp>cl bug.cpp 
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23918 for x86 
Copyright (C) Microsoft Corporation. All rights reserved. 

bug.cpp 
bug.cpp(19): fatal error C1001: An internal error has occurred in the compiler. 
(compiler file 'msc1.cpp', line 1433) 
To work around this problem, try simplifying or changing the program near the locations listed above. 
Please choose the Technical Support command on the Visual C++ 
Help menu, or open the Technical Support help file for more information 
Internal Compiler Error in C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\cl.exe. You will be prompted to send an error report to Microsoft later. 
INTERNAL COMPILER ERROR in 'C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\cl.exe' 
    Please choose the Technical Support command on the Visual C++ 
    Help menu, or open the Technical Support help file for more information 

Từ một số thí nghiệm, nó sẽ xảy ra rằng cả hai operator* định nghĩa là cần thiết cho các lỗi xuất hiện. Nếu tiền tố hoặc phiên bản postfix bị xóa, mã mẫu có thể biên dịch tốt.

Tôi có thể điền vào một báo cáo lỗi trên Microsoft nếu hành vi này được xác nhận là lỗi và chưa phải là vấn đề nổi tiếng của trình biên dịch.

+0

Để trình gỡ xuống: bạn có thể giải thích quan điểm của bạn không? – prapin

+7

Kẻ hủy diệt phải là người ghét SFINAE, người có thể đổ lỗi cho họ. Dù sao, một lỗi biên dịch nội bộ là * luôn luôn * một lỗi trình biên dịch. – Praetorian

+1

@Praetorian Vâng, tôi cũng nghĩ vậy. Nhưng tài liệu của Microsoft dường như chỉ ra rằng đó là lỗi người dùng nếu anh ta bị rơi trình biên dịch của họ ... – prapin

Trả lời

4

Theo dự thảo hiện tại của chuẩn C++:

14.1 Template parameters [temp.param] 
1 The syntax for template-parameters is: 
template-parameter: 
    type-parameter 
    parameter-declaration 
type-parameter: 
    type-parameter-key ...opt identifieropt 
    type-parameter-key identifieropt= type-id 
    template < template-parameter-list > type-parameter-key ...opt identifieropt 
    template < template-parameter-list > type-parameter-key identifieropt= id-expression 
type-parameter-key: 
    class 
    typename 

Theo kết quả bạn có lỗi cú pháp (bạn có thể báo cáo MS về điều đó trình biên dịch không phát hiện lỗi như vậy). Vì vậy, trong trường hợp của bạn đúng mã được hình thành chính là:

template<int M> 
class BaseUnit 
{ 
public: 
    constexpr explicit BaseUnit(double aValue) : value(aValue) {} 
    template<typename U, typename T = typename std::enable_if<std::is_arithmetic<U>::value, int>::type> 
    BaseUnit<M> operator*(U scalar) const { return BaseUnit<M>(value * scalar); } 
    template<typename U, typename T = typename std::enable_if<std::is_arithmetic<U>::value, int>::type> 
    friend BaseUnit operator* (U scalar, BaseUnit v) { return BaseUnit(scalar*v.value); } 
protected: 
    double value; 
}; 

int main() 
{ 
    BaseUnit<1> a(100); 
    a = 10 * a; // ok 
    a = "19" * a; // error 
    return 0; 
} 
+0

Bạn không giải thích điều gì sai với mã gốc, nếu có. – Oktalist

+0

lỗi cú pháp như bạn có thể thấy – AnatolyS

+0

Mã của bạn biên dịch mà không có lỗi trên VS2015, cảm ơn bạn. Nhưng có một lỗi biên dịch trên Clang: 'error: need 'typename' trước 'std :: enable_if :: giá trị, int> :: type' vì 'std :: enable_if :: giá trị, int> 'là một phạm vi phụ thuộc'. Vì vậy, cú pháp thực sự được định dạng tốt có lẽ là 'template :: value, int> :: type>' – prapin

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