2012-08-28 34 views
11

考慮下面的代碼:if/else在編譯時?

#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)是沒有問題的。但是,即使if/else中的條件在編譯時已知,y(const數據類型)也會導致錯誤。

編譯時是否有可能不編譯錯誤條件?

+4

你想要的是一個'靜態if',它不是一部分的c + +(http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Static-If-I-Had-a-Hammer) – arnoo

回答

11

最簡單的解決方法是局部模板特殊化:

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

另一種選擇是代表團:

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是另一種選擇,但通常不是首選f或者這種情況下:

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

如果else分支沒有被編譯,那麼你的函數會有完全不同的含義。你不能只編譯你的部分代碼。如果你不希望它執行,不要寫它。這不像函數每次被調用時都要單獨編譯。

類型系統的全部意義在於避免意外地嘗試執行諸如指定const變量之類的操作。你將不得不寫一個全新的(或重載的)函數,它不會分配給那個變量。

3

爲給定類型編譯類模板。即使控制流沒有到達分配,也會編譯該分配。由於該成員是const,編譯將失敗。

您可以使用某種形式的SFINAE來跳過該作業,但它不會像現在這樣工作。

這工作(我已經刪除了簡單的testTernary成員函數):

#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

您可以專門的類常量類型

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

試試這個:

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

    } 
};