'const'的C ++模板

时间:2014-09-12 07:07:48

标签: c++ templates const derived-class

考虑以下模板类:

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的工作方式与之前的情况相同。

  1. 所以似乎要么&#39; const T&amp; x&#39;或者&#39; T const&amp; x&#39;在模板类中暗示&#39; float * const&amp; x&#39;在派生类中。这是对的吗?
  2. 如果我想要&#39; const float *&amp; x&#39; (或者&#39; const float * x&#39;)在派生类中,应该是我的模板类函数?
  3. 谢谢。

3 个答案:

答案 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;直接进入那里。

我看到两个选项。其一,如果这种使用是Functionconst 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*内某处evaltemplate <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 &xT 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*>