C++带有'const'的模板

13

Consider the following template class:

template <typename T> class Function {
public:
    virtual float eval( const T &x, const T &y ) = 0;
};

因为'eval'函数不应该修改两个输入值'x'和'y'的值,所以我将它们设为“const”。 然后我创建了以下从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类。编译器报错说函数“eval”未实现。 为了让编译器满意,派生类必须如下所示:

class Foo2 : public Function <float*> {
public:
    Foo2() : Function <float*> () {}
    virtual float eval( float* const &x, float* const &y ) { ... }
};

Foo2::eval函数使用了两个类型为'float * const'的参数,而不是'const float *'。换句话说,Foo2::eval可以修改数组'x'和'y'的内容,这不是我想要的。

我尝试将模板类'Function'更改如下:

    virtual float eval( T const &x, T const &y ) = 0;

但是类Foo1仍然无法工作,而类Foo2与之前的情况相同。
- 因此看起来模板类中的'const T &x'或'T const &x'都意味着派生类中的'float * const & x'。这是正确的吗? - 如果我想在派生类中使用'const float * & x'(或'const float * x'),我的模板类Function应该是什么?
谢谢。
3个回答

9
您观察到的行为在标准范围内是100%正确的。这是“常量指针”与“指向常量的指针”的典型示例。
您的主要模板声明它采用“对T的引用,通过该引用无法修改被引用的T对象”(语法为const T&,相当于T const &)。
然后,您使用类型float*实例化模板,即“指向float的指针”。由此可知,在模板参数替换后,函数参数类型确实是“对float*的引用,通过该引用无法修改被引用的float*”。无法直接将“无法修改指向所指向的float的float*”偷偷塞进去。
我看到有两个选项。一种是,如果这种用法是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
};

如果这不是你的选项(例如,如果你需要在 Function 内的某个地方使用 float *,而在其他地方使用 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) { ... }
};

3
似乎在模板类中 const T &xT const &x 都意味着在派生类中有 float* const &x。这是正确的吗?
是的,这是正确的。思考的方式是 T 总是 const;在你的情况下,T 恰好是指针。
如果我想要在派生类中使用 const float* &x(或者 const float* x ),那么我的模板类应该怎么写呢?
听起来应该是 class Foo2 : public Function <const float*>

0
一种解决方法是针对指针类型部分特化Function,以便为eval使用不同的签名:
 template <typename T> class Function<T*> {
    public:
      virtual float eval( const T* x, const T* y ) = 0;
 };

或者,你可以从Function<const float*>派生出Foo2


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接