带有 'const' 的 C++ 模板

标签 c++ templates constants derived-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 和以前的情况一样。

  1. 因此,模板类中的“const T &x”或“T const &x”似乎暗示派生类中的“float* const &x”。这是正确的吗?
  2. 如果我想在派生类中使用“const float* &x”(或“const float* x”),我的模板类 Function 应该是什么?

谢谢。

最佳答案

就标准而言,您观察到的行为是 100% 正确的。这是“常量指针”与“指向常量的指针”的经典示例。

您的主模板声明它采用“对 T 的引用,它不能通过它修改被引用的 T 对象”(语法是 const T & ,等同于T const &)。

然后,您使用 float* 类型实例化模板,即“指向 float 的指针”。由此可知,模板参数替换后的函数参数类型确实是“对float *的引用,无法通过它修改所引用的float *开头”。无法直接将“无法修改 float * 指向的 float”直接走私到那里。

我看到两个选项。第一,如果这种用法是 FunctionT 的唯一用法,只需使用 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 * 某处 Functionconst 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) { ... }
};

关于带有 'const' 的 C++ 模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25802658/

相关文章:

c++ - 添加基于模板参数的拷贝构造函数

C++ STL 常量迭代器和常量指针

c++ - 如何使用 std::array 模拟 C 数组初始化 "int arr[] = { e1, e2, e3, ... }"行为?

c++ - 制作预编译代码/数据结构

c++ - 如何在调用处替换内联函数代码?

c++ - 一种从 .STL(立体光刻)文件计算质心的方法?

c++ - 检查模板参数是否有成员函数

C++ static const 和初始化(有没有惨败)

c++ - 在 C++ 中定义常量 C 字符串的正确方法?

c++ - QML [未定义] 错误