在模板函数参数列表中忽略常量

Const being ignored in template function parameter list

本文关键字:常量 列表 参数 函数      更新时间:2023-10-16

我在模板类中的函数定义方面遇到了问题。

我有一个模板类Array,它有一个成员函数IndexOf

// Defined in header
template <typename T>
class Array {
// Other stuff
int IndexOf(const T value) const {
// Code of function
};
// Other stuff
};

当我使用类指针创建数组的实例时,该函数忽略const T,只使用T。所以当我用const T调用函数时,会出现一个编译器错误:"没有重载函数的实例":

#include "Array.h"
class Object{
// Object stuff
};
int main(){
// Demonstration code
Array<Object*> objects = Array<Object*>(); // Array of Object*
Object* obj = new Object();                // An Object*
const Object* cobj = new Object();         // A const Object*
// This works fine
objects.IndexOf(obj); // No problems
// This has compile error
objects.IndexOf(cobj); // No idea why
delete obj;
delete cobj;
return 0;
}

代码似乎忘记了函数的参数是const T。函数参数应该是const Object*的,但它将参数视为Object*

知道为什么会这样吗?

如果我不使用指针作为类型,则不会发生错误。

函数中的代码不会引起问题。

在说之前,不,我不将使用std::vector或其他类似的方式来动态调整数组的大小。这带走了所有的乐趣。

实际上,函数的声明可以看作是:

IndexOf(const (Object *) val)

这基本上意味着Object *应该指向 const 对象,如下所示:

Object *const cobj = new Object();

现在您将拥有正确的行为。 但是,如果您真的对 const 指针感兴趣,则需要将声明修改为:

Array<const Object *> objects;

const T valueT在哪里Object*Object* const valueconst T value中的const适用于value,不会修改Tconst T value是无法更改的T类型的value,对于指针来说,这意味着无法分配新地址。很明显,以下函数无法使用const Object *调用。

int IndexOf(Object * const value) const // const pointer to non-const Object

若要向指向类型添加const性,可以使用类型特征来获取指向类型,向其添加 const,然后从中生成新的指针类型。例如:

#include <type_traits>
template<class T>
using add_const_to_ptr =
std::add_pointer_t<
std::add_const_t<
std::remove_pointer_t<T>>>;

其用法如下所示:

template<class T>
struct container {
void push(add_const_to_ptr<T> ptr) {
(void)ptr;
}
};
struct bar {};
int main()
{
const bar cbar;
bar mbar;
container<bar*> my_container;
my_container.push(&mbar);
my_container.push(&cbar);
}

尽管这假设container将仅与指针一起使用,但在这种情况下,最好T引用指向的对象类型,而不是指针类型。如果T可能是也可能不是指针类型,则可以通过检查T是否实际上是带有std::conditional的指针来改进类型特征:

#include <type_traits>
template<class T>
using add_const_to_ptr =
std::conditional_t<std::is_pointer<T>::value,
std::add_pointer_t<
std::add_const_t<
std::remove_pointer_t<T>>>,
T>;

您可以将Array<Object*>::IndexOf()声明为模板:

template <typename U>
int IndexOf(const U& value) const {
// Code of function
}

在里面,您将value与数组的内容进行比较,该比较会将内容从Object*转换为const Object*这当然是允许的。

同样使用这种方法,您可以将T可以转换的任何内容传递给该函数。