考虑以下模板类:
template <typename T> class Function {
public:
virtual float eval( const T &x, const T &y ) = 0;
};
因为&#39; eval&#39;功能不应该修改两个输入的值&#39; x&#39;并且&#39; y&#39;,我把它们作为&#39; const&#39;。 然后我创建从Function
派生的以下类class Foo1 : public Function <float*> {
public:
Foo1() : Function <float*> () {}
virtual float eval( const float* &x, const float* &y ) { ... }
};
当我使用g ++编译时,我收到以下警告:
hidden overloaded virtual function 'Function<float *>::eval' declared here: type mismatch at 1st parameter
('float *const &' vs 'const float *&')
virtual float eval( const T &x, const T &y ) = 0;
我无法实例化类Foo1。编译器说函数&#39; eval&#39;没有实施。 为了使编译器满意,派生类必须如下:
class Foo2 : public Function <float*> {
public:
Foo2() : Function <float*> () {}
virtual float eval( float* const &x, float* const &y ) { ... }
};
Foo2 :: eval函数使用两个类型为&#39; float * const&#39;的参数。而不是&#39; const float *&#39;。换句话说,Foo2 :: eval可以修改数组的内容&#39; x&#39;和&#39;。这不是我想要的。
我试图更改模板类&#39;功能&#39;如下:
virtual float eval( T const &x, T const &y ) = 0;
但是类Foo1仍然不起作用,类Foo2的工作方式与之前的情况相同。
谢谢。
答案 0 :(得分:8)
就标准而言,您观察到的行为是100%正确的。它是&#34;常量指针&#34;的典型例子。与&#34;指向常数的指针。&#34;
您的主要模板声明它需要T
引用T
,它无法修改被引用的const T &
对象&#34; (语法为T const &
,相当于float*
)。
然后,您使用类型float
实例化模板,即&#34;指向float *
的指针。&#34;由此得出,模板参数替换后的函数参数类型确实是对float *
的引用,它不能通过它来修改所引用的float
开始。&#34;没有办法走私&#34;无法修改float *
被引用的T
点&#34;直接进入那里。
我看到两个选项。其一,如果这种使用是Function
中const float *
的唯一用途,只需使用T
作为模板参数,因为class Foo1 : public Function <const float*> {
public:
Foo1() : Function <const float*> () {}
virtual float eval( const float* const &x, const float* const &y ) { ... }
// notice two `const` keywords above: one for the pointed object, one for the reference
};
你真的是float *
想:
Function
如果这不是您的选择(即如果您需要const float*
内某处eval
和template <class T>
struct unmodifiable {
typedef const T &type;
};
template <class T>
struct unmodifiable<T*> {
typedef const T* const &type; // if you want to keep the reference
// or just:
// typedef const T *type; // if you don't want to bother with the reference for pointer types
};
template <typename T> class Function {
public:
virtual float eval( typename unmodifiable<T>::type x, typename unmodifiable<T>::type y ) = 0;
};
class Foo1 : public Function <float*> {
public:
Foo1() : Function <float*> () {}
virtual float eval( unmodifiable<float*>::type x, unmodifiable<float*>::type y ) { ... }
// or just spell it out exactly, based on the variant of `unmodifiable` you've chosen, e.g.:
// virtual float eval (const float *x, const float *y) { ... }
};
其他地方),您必须使用某些类型特征并修改{{1}}的参数。像这样:
{{1}}
答案 1 :(得分:1)
模板类中的
const T &x
或T const &x
似乎在派生类中隐含float* const &x
。这是对的吗?
是的,这是对的。考虑它的方法是T
总是const
;在你的情况下T
碰巧是一个指针。
如果我想在派生类中使用
const float* &x
(或const float* x
),那么我的模板类函数应该是什么?
听起来应该是class Foo2 : public Function <const float*>
。
答案 2 :(得分:0)
一种方法是对指针类型进行部分特化Function
,以便为eval
使用不同的签名:
template <typename T> class Function<T*> {
public:
virtual float eval( const T* x, const T* y ) = 0;
};
或者,您可以从Foo2
派生Function<const float*>
。