2016-06-30 16 views
7

Ho un codice C++ 11 che non riesce a compilare su Visual Studio 2015 (Update 2), ma compila senza errori sia su Clang che su GCC. Pertanto, sospetto un bug del compilatore in Visual Studio, ma forse il mio codice è in qualche modo mal formato.Errore C1001 su Visual Studio 2015 con std :: enable_if

La mia classe reale BaseUnit è una classe wrapper di modello su un valore double, che si occupa delle dimensioni fisiche delle quantità (espresse come unità di misura m, kg, s, K). Ad esempio, la moltiplicazione di una velocità con un'istanza di modello Time assegna automaticamente un'istanza Distance. Il problema si verifica con l'implementazione corrente della moltiplicazione con uno scalare. Ho semplificato la classe il più possibile per mostrare il problema.

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

Quando si compila su Visual Studio, quali che siano le opzioni della riga di comando, un errore interno C1001 appare:

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 

Da alcuni esperimenti, capita che sia operator* definizioni sono necessari per apparire l'errore. Se viene rimosso il prefisso o la versione postfix, il codice di esempio può essere compilato correttamente.

È possibile che compili un bug report su Microsoft se si conferma che questo comportamento è un bug e non è già un problema noto del compilatore.

+0

Al downvoter: potrebbe spiegare il vostro punto? – prapin

+7

I downvoter devono essere qualcuno che odia SFINAE, che può biasimarli. Ad ogni modo, un errore interno del compilatore è * sempre * un bug del compilatore. – Praetorian

+1

@Praetorian Sì, lo penso anche io. Ma la documentazione di Microsoft sembra indicare che è colpa dell'utente se si è bloccato il compilatore ... – prapin

risposta

4

Secondo l'attuale progetto di standard del 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 

Come risultato si ha errore di sintassi (è possibile segnalare a MS in merito che il compilatore non rileva tale errore). Quindi nel tuo caso corretto codice di ben formato è:

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

Non hai spiegato cosa c'era di sbagliato nel codice originale, se non altro. – Oktalist

+0

errore di sintassi come si può vedere – AnatolyS

+0

Il codice viene compilato senza errori su VS2015, grazie. Ma c'è un errore di compilazione su Clang: 'errore: serve 'typename' prima 'std :: enable_if :: value, int> :: type' because 'std :: enable_if :: value, int> 'è un ambito dipendente'. Quindi la vera sintassi ben strutturata è probabilmente 'template :: value, int> :: type>' – prapin

Problemi correlati