2016-06-30 18 views
7

Mam trochę kodu C++ 11, który nie kompiluje się w Visual Studio 2015 (aktualizacja 2), ale kompiluje bez błędów zarówno w Clang i GCC. Dlatego podejrzewam błąd kompilatora w Visual Studio, ale może mój kod jest w jakiś sposób źle sformułowany.Błąd C1001 w programie Visual Studio 2015 ze std :: enable_if

Moja prawdziwa klasa BaseUnit jest klasą opakowania szablonu o wartości double, dbając o fizyczne wymiary ilości (wyrażone jako jednostki SI m, kg, s, K). Na przykład mnożenie instancji szablonu Prędkość za pomocą czasu automatycznie daje instancję Odległość. Problem występuje przy bieżącej implementacji mnożenia przez skalar. Uprościłem klasę tak bardzo, jak tylko mogłem, aby pokazać problem.

#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; 
} 

Podczas kompilacji w Visual Studio, niezależnie od opcji wiersza poleceń, wewnętrzny błąd C1001 pojawia:

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 

Od niektórych doświadczeniach, zdarza się, że potrzebne są obie definicje operator* na pojawienie się błędu. Jeśli usunięty zostanie prefiks lub wersja posifix, przykładowy kod może się skompilować dobrze.

Mogę wypełnić zgłoszenie błędu w firmie Microsoft, jeśli to zachowanie zostanie potwierdzone jako błąd, a nie jest już znanym problemem kompilatora.

+0

Do odźwiernika: czy mógłbyś wyjaśnić swój punkt widzenia? – prapin

+7

Wadą musi być ktoś, kto nienawidzi SFINAE, który może ich winić. W każdym razie wewnętrzny błąd kompilatora jest zawsze * błędem kompilatora. – Praetorian

+1

@Praetorian Tak, myślę, że również. Ale dokumentacja Microsoftu zdaje się wskazywać, że to wina użytkownika, który zniszczył ich kompilator ... – prapin

Odpowiedz

4

Według obecnego projektu standardu 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 

W efekcie masz błąd składni (można zgłosić MS o tym kompilator nie wykrywa takiego błędu). Tak więc w twoim przypadku poprawny, dobrze napisany kod to:

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

Nie wyjaśniłeś, co było nie tak z oryginalnym kodem, jeśli w ogóle. – Oktalist

+0

błąd składniowy, jak widać – AnatolyS

+0

Twój kod kompiluje się bez błędu na VS2015, dziękuję. Ale jest błąd kompilacji na Clangu: 'error: need 'typename' before 'std :: enable_if :: value, int> :: type' ponieważ 'std :: enable_if :: value, int> 'to zakres zależny'. Tak więc prawdziwa dobrze sformułowana składnia to prawdopodobnie 'szablon :: value, int> :: type>' – prapin

Powiązane problemy