2016-08-12 84 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)