2012-08-28 8 views
11

Xét đoạn mã sau:nếu/ở thời điểm biên dịch?

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

Đối với x (không const) không có vấn đề. Nhưng y (kiểu dữ liệu const) gây ra lỗi ngay cả khi điều kiện trong if/else được biết tại thời gian biên dịch.

Có khả năng nào để không biên dịch điều kiện giả tại thời gian biên dịch không?

+4

Những gì bạn muốn là một 'if' tĩnh, và nó không phải là một phần của C++ (http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Static-If-I-Had-a-Hammer) – arnoo

Trả lời

11

Việc sửa chữa đơn giản nhất là một phần mẫu chuyên môn:

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

lựa chọn khác là Đoà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 là một tùy chọn khác, nhưng thường không được ưa thích f hoặc trường hợp này:

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

Nếu nhánh khác không được biên dịch, thì hàm của bạn sẽ có ý nghĩa hoàn toàn khác. Bạn không thể không biên dịch một phần mã của mình. Nếu bạn không muốn nó thực thi, đừng viết nó. Nó không giống như chức năng được biên dịch riêng biệt cho mỗi lần nó được gọi.

Toàn bộ điểm của hệ thống loại là tránh vô tình cố gắng thực hiện những việc như chỉ định cho các biến số const. Bạn sẽ phải viết một hàm hoàn toàn mới (hoặc quá tải) mà không gán cho biến đó.

3

Mẫu lớp được biên dịch cho loại đã cho. Ngay cả khi luồng điều khiển không nhận được nhiệm vụ, nhiệm vụ đó cũng được biên dịch. Vì thành viên là const, việc biên dịch sẽ thất bại.

Bạn có thể sử dụng một số hình thức SFINAE để bỏ qua nhiệm vụ đó, nhưng nó sẽ không hoạt động như hiện tại.

này hoạt động (Tôi đã gỡ bỏ chức năng testTernary viên vì đơn giản):

#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

Bạn có thể chuyên lớp với nhiều loại 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

Hãy thử điều này:

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

    } 
};