2012-08-28 13 views
11

Consideremos el siguiente código:if/else en tiempo de compilación?

#include <iostream> 
#include <type_traits> 

template<typename T> class MyClass 
{ 
    public: 
     MyClass() : myVar{0} {;} 
     void testIf() { 
      if (isconst) { 
       myVar; 
      } else { 
       myVar = 3; 
      } 
     } 
     void testTernary() { 
      (isconst) ? (myVar) : (myVar = 3); 
     } 

    protected: 
     static const bool isconst = std::is_const<T>::value; 
     T myVar; 
}; 

int main() 
{ 
    MyClass<double> x; 
    MyClass<const double> y; 
    x.testIf(); 
    x.testTernary(); 
    y.testIf(); // <- ERROR 
    y.testTernary(); // <- ERROR 
    return 0; 
} 

Para x (no const) no hay ningún problema. Pero y (tipo de datos const) causa un error incluso si la condición en if/else se conoce en tiempo de compilación.

¿Hay alguna posibilidad de no compilar la condición falsa en tiempo de compilación?

+4

Lo que queremos es un 'if' estática, y no es parte de C++ todavía (http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Static-If-I-Had-a-Hammer) – arnoo

Respuesta

11

La solución más simple es la especialización de plantilla parcial:

template<typename T> class MyClassBase 
{ 
    public: 
     MyClassBase() : myVar{0} {;} 

    protected: 
     T myVar; 
}; 

template<typename T> class MyClass: MyClassBase<T> 
{ 
    public: 
     void testIf() { myVar = 3; } 
}; 

template<typename T> class MyClass<const T>: MyClassBase<const T> 
{ 
    public: 
     void testIf() { myVar; } 
}; 

Otra opción es la delegación:

template<typename T> class MyClass 
{ 
    public: 
     MyClass() : myVar{0} {;} 
     void testIf() { testIf_impl(std::integral_constant<bool, isconst>()); } 

    protected: 
     static const bool isconst = std::is_const<T>::value; 
     T myVar; 

    private: 
     void testIf_impl(std::true_type) { myvar; } 
     void testIf_impl(std::false_type) { myVar = 3; } 
}; 

SFINAE es otra opción, pero en general no se prefiere f o este caso:

template<typename T> class MyClass 
{ 
    public: 
     MyClass() : myVar{0} {;} 
     template 
     <typename U = void> 
     typename std::enable_if<std::is_const<T>::value, U>::type testIf() { myvar; } 
     template 
     <typename U = void> 
     typename std::enable_if<!std::is_const<T>::value, U>::type testIf() { myvar = 3; } 

    protected: 
     static const bool isconst = std::is_const<T>::value; 
     T myVar; 
}; 
1

Si la rama else no se compiló, entonces su función tendría un significado completamente diferente. No puedes simplemente no compilar parte de tu código. Si no quiere que se ejecute, no lo escriba. No es como si la función se compilara por separado para cada vez que se llame.

El objetivo de un sistema de tipos es evitar accidentalmente hacer cosas como asignar a las variables const. Debería escribir una función completamente nueva (o sobrecargada) que no se asigna a esa variable.

3

La plantilla de clase se compila para el tipo dado. Incluso si el flujo de control no llega a la asignación, esa asignación también se compila. Como el miembro es const, la compilación fallará.

Puede usar alguna forma de SFINAE para omitir esa asignación, pero no va a funcionar como lo está haciendo ahora.

Esto funciona (He quitado la función testTernary miembro por simplicidad):

#include <iostream> 
#include <type_traits> 

template<typename T> class MyClass 
{ 
    public: 
     MyClass() : myVar{0} {;} 

     template<class U = T> 
     typename std::enable_if<std::is_const<U>::value>::type testIf() { 
      myVar; 
     } 

     template<class U = T> 
     typename std::enable_if<!std::is_const<U>::value>::type testIf() { 
      myVar = 3; 
     } 

    protected: 
     static const bool isconst = std::is_const<T>::value; 
     T myVar; 
}; 

int main() 
{ 
    MyClass<double> x; 
    MyClass<const double> y; 
    x.testIf(); 
    y.testIf(); 
    return 0; 
} 
5

Usted puede especializarse la clase de tipos const

template<typename T> 
class MyClass 
{ 
    // Whatever you need to do 
}; 

template<typename T> 
class MyClass<const T> 
{ 
    // Whatever you need to do for const types 
}; 
0

Prueba esto:

template<typename T> 
class MyClass 
{ 
    T myVar; 
public: 
    MyClass() : myVar(0) {} 

    void testIf() 
    { 
     assign(myVar, 3); 
    } 
private: 

    template<typename V> 
    void assign(V& destination, int value) 
    { 
     destination = value; 
    } 
    template<typename V> 
    void assign(const V& destination, int value) 
    { 

    } 
}; 
Cuestiones relacionadas