2012-08-28 15 views
11

Rozważmy następujący kod:jeśli/else w czasie kompilacji?

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

X (const) nie ma problemu. Ale y (stały typ danych) powoduje błąd, nawet jeśli warunek w/else jest znany podczas kompilacji.

Czy istnieje możliwość nie kompilowania fałszywego warunku podczas kompilacji?

+4

Co chcesz to 'static if' i nie jest częścią z C++ (http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Static-If-I-Had-a-Hammer) – arnoo

Odpowiedz

11

Najprostszą jest częściowa specjalizacja szablonu:

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

Inną opcją jest delegacja:

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 to kolejna opcja, ale generalnie nie jest preferowana czy to przypadek:

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

Jeśli gałąź else nie została skompilowana, twoja funkcja miałaby zupełnie inne znaczenie. Nie możesz po prostu nie skompilować części kodu. Jeśli nie chcesz, aby był wykonywany, nie pisz tego. Nie jest tak, że funkcja jest kompilowana osobno dla każdego jej wywołania.

Cały punkt systemu typu polega na tym, aby uniknąć przypadkowego próbowania zmian w przypisaniach do zmiennych const. Musiałbyś napisać całkowicie nową (lub przeciążoną) funkcję, która nie przypisuje tej zmiennej.

3

Szablon klasy zostaje skompilowany dla danego typu. Nawet jeśli przepływ kontrolny nie dociera do zadania, to zadanie jest również kompilowane. Ponieważ element członkowski jest const, kompilacja zakończy się niepowodzeniem.

Możesz użyć jakiejś formy SFINAE, aby pominąć to zadanie, ale nie zadziała tak jak teraz.

To działa (I usunęliśmy funkcji testTernary użytkownika dla uproszczenia):

#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

Można specjalizować klasę dla const typów

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

Spróbuj tego:

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) 
    { 

    } 
}; 
Powiązane problemy