在模板函数参数列表中忽略常量
Const being ignored in template function parameter list
我在模板类中的函数定义方面遇到了问题。
我有一个模板类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 value
T
在哪里Object*
是Object* const value
。const T value
中的const
适用于value
,不会修改T
。const 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
可以转换的任何内容传递给该函数。
- 不能在初始值设定项列表中将非常量表达式从类型 'int' 缩小到'unsigned long long'
- 如何在 c++ stl 中获取列表中被推回的元素的地址,在常量时间内?
- 无法在声明时使用初始值设定项列表初始化常量字符*/字符串数组的向量
- 在模板函数参数列表中忽略常量
- 对列表中的任意元素的常量时间访问 (C++)
- 常量变量初始化仅与成员初始化列表一起工作
- 初始化列表中常量变量的"this"关键字
- 如何使可变 lambda 捕获列表的某些成员变得非常量
- 从类型为"<大括号括起来的初始值设定项列表>"的类型非常量引用的无效初始化
- 初始化列表中的随机常量
- C++中非常量列表迭代器的奇怪行为
- 列表的迭代器可以返回非常量引用吗?
- 如何在c++中创建一个列表及其内容常量
- 实现常量对象列表
- C++:在初始化列表中传递一个常量 *p
- C++ 中常量列表的迭代器<t>
- 为什么允许在初始值设定项列表中从常量指针到常量到常量指针到非常量进行转换
- 初始化字符串的静态常量列表
- 键常量列表
- 这有多危险?(列表<T>正在强制转换为列表<常量 T>)