2016-08-12 121 views
2

我在這裏做了一個小型的研究,這需要在某個階段,我有不同的類在某些數據上做(或不做)操作,這取決於它的常量。const類型的C++模板泛化

一個小例子是這樣的(http://coliru.stacked-crooked.com/a/75c29cddbe6d8ef6

#include <iostream> 

template <class T> 
class funny 
{ 
public: 
    funny(T& a) : v(a) {v -= 1; } 
    virtual ~funny() { v += 1; } 
    operator T() {return v;} 

private: 
    T& v; 
}; 

#define V(a) funny<decltype(a)>(a) 

int main() 
{ 
    char t[] = "ABC"; // <-- HERE 

    if(V(t[0]) == (char)'A') 
    { 
     std::cout << "Pass" << t[0]; 
    } 
    else 
    { 
     std::cout << "No Pass" << t[0]; 
    } 
} 

現在,問題來了:

如果我修改了行標<-- HERE

const char t[] = "ABC"; 

我得到以下編譯錯誤:

main.cpp: In instantiation of 'funny<T>::funny(T&) [with T = const char&]': 
main.cpp:21:7: required from here 
main.cpp:7:28: error: assignment of read-only location '((funny<const char&>*)this)->funny<const char&>::v' 
    funny(T& a) : v(a) {v -= 1; } 
         ~~^~~~ 
main.cpp: In instantiation of 'funny<T>::~funny() [with T = const char&]': 
main.cpp:21:7: required from here 
main.cpp:8:27: error: assignment of read-only location '((funny<const char&>*)this)->funny<const char&>::v' 
    virtual ~funny() { v += 1; } 
        ~~^~~~ 

這是完全可以理解的,因爲我嘗試修改常量。編譯器就在這裏。可是,我真的需要這個工作也爲const的數據,所以我試圖創建模板的一個const專業化:

template <class T> 
class funny <T const> 
{ 
public: 
    funny(const T& a) : v(a) {} 
    operator T() {return v;} 

private: 
    const T& v; 
}; 

但無論如何,編譯器沒有找到它,並仍試圖編譯非const版本。

有關如何實現此目的的任何想法?

+2

正如你可以在錯誤信息,'T'被推斷爲'爲const char&',這是一個參考,請參閱type,因此不是const限定的('T'是'X&',其中'X'是'const char')。這是因爲't [0]'是一個表達式和一個表達式,是一個左值。這種表達式的decltype(e)產生一個左值參考類型。 – dyp

回答

1

編譯如果你改變:

template <class T> 
class funny <T const> 

到:

template <class T> 
class funny <const T&> 
+0

確實如此:)謝謝! – fritzone

+1

請注意,這是因爲'decltype(t [0])'是一個參考。這對於一些'const char'不起作用。 @Miles的答案更強大。 – TartanLlama

+0

@TartanLlama我同意 – marcinj

4

decltype(t[0])演繹到const char&,這不符合您的const char專業化。您有兩種選擇:

1)將您的專業化改爲template <class T> class funny <T const&>。這將適用於這種情況,但不適用於const int FOO = 42; V(FOO);

2)更改V宏一直演繹到非引用類型:

#define V(a) funny<typename std::remove_reference<decltype(a)>::type>(a)