不理解C ++类型不匹配:const Foo * 到 Foo * const & 的含义

8

有以下一组对象和语句:

QSet<Foo*> set;
iterator QSet::insert(const T & value)    //type of the function I want to call
const Foo * get() const                   //type of the function I use to get the argument

set.insert(get());                        //the line showing up as error

我遇到了错误信息"no known conversion for argument 1 from 'const Foo*' to 'Foo* const&",由于我不太理解这些类型,所以我不知道该怎么做才能让它正常工作。
据我所知,const关键字应用于其左侧的类型,但顶层const可以写在其适用的类型左侧。我的猜测是我需要将get()转换为引用,但我不确定如何做到这一点。

这不是“顶层const”。get()返回一个指向“const Foo”的指针,而不是一个const指针。 - Barry
那么我的理解是,一个以 const 开头的东西适用于其右侧的所有内容,这是错误的吗?那么这样的 const 到底适用于什么呢? - Balz Guenat
4个回答

8

这里似乎有几个误解(包括提问者和一些回答)。

首先,你说“我的猜想是我必须将get()转换为引用,但我不确定如何做。” 让我们来澄清一下:

1)“我必须将get()转换为引用” - 实际上,你不需要这样做!

iterator QSet::insert(const T & value)确实接受一个引用。 但它是对类型T的引用。 所以问题是,“T是什么类型?”

在这种情况下,T=Foo *。 因此,在此模板实例中,insert实际上是:

iterator QSet::insert(Foo * const & value) - 从右到左读取: insert接受对指向Foo的常量指针的引用。

2) "我不确定如何将指针转换为引用" -- 虽然你不必在这里这样做,但通常你需要通过对 get 的结果进行解除引用来实现。例如:*(get())

其次,编译器错误。该错误是由于存在冲突造成的:

a)get() 返回一个 const Foo *

b)但是 set 存储的是一个 Foo* -- 而不是一个 const Foo *,所以 insert 只接受可变的 Foo

因此,您无法在您的 QSet<Foo*> 中存储一个常量指针。这是有道理的,因为您可以使用 set 访问和更改其中的 Foo,而您承诺不会对 const Foo 进行更改。

这个参考资料应该很有帮助:

https://isocpp.org/wiki/faq/const-correctness

您可能还会想是否可以只使用 QSet<Foo> 而不是 QSet<Foo*>。在前者的情况下,事情很可能会按照您的预期运行。


1
看 https://isocpp.org/wiki/faq/const-correctness#const-ref-alt,是否真的对于任意复杂类型构造 Xconst X* 等同于 X const* - Balz Guenat
X是一种类型时 - 而不是如果X更复杂时。事实上,这就是为什么在替换T之前必须进行交换的原因。将其写为X const*使得从右到左阅读更容易(“指向常量X的指针”)。但是,将其写为const X*在源代码中更明显地表明该类型是“常量X”。因此,通常在代码中看到它是const X* - Corey
关于模板这个问题可能会有点混淆,所以……只要编写 QSet 的人可以编写 insert(const T & value)insert(T const & value),它们是相同的。但那是因为编译器知道该怎么做。如果想在纸上或者脑海中替换掉 T,则在进行替换之前必须将其视为 insert(T const & value) - Corey
那么 const (int *) * pcp 是指向一个常量指针的指针,指向一个整数?还是这是一个无效的情况? - Balz Guenat
2
我认为您不能那样使用括号。 g ++会给我编译器错误。没有括号,const int ** pcp将是一个可改变的指向常量int的可改变指针,而int * const * pcp将是一个可变指针到可变 int的常量指针。 - Corey

5
你正在尝试将一个const Foo * 插入到一个QSet<Foo *> 中,但编译器不会自动将const Foo * 转换为普通的Foo *

1
@Jeffrey:因为QSet<Foo *>包含非const指针。你不能隐式地将指向const的指针转换为指向非const的指针。 - Greg Hewgill

3
我通过将集合的类型更改如下来解决了这个问题。
QSet<Foo const*> set;

通过这个更改,编译成功了。


3
你正在违反从你的 get() 函数返回的指针的常量性。 get() 返回一个指向类型为 Foo 的常量对象的指针,但是然后您尝试将其插入非常量 Foo 指针的向量中。 您需要对来自 get() 的返回值进行 const_cast 或更改 get() 的返回类型,从 const Foo* 更改为 Foo*

这将是另外两个选择。 - Balz Guenat

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