为什么指针向量不能转换为const指针的const向量?

Gav*_*ith 15 c++ casting const

该类型 vector<char *>不可转换为const vector<const char*>.例如,以下内容给出了编译错误:

#include <vector>

using namespace std;

void fn(const vector<const char*> cvcc)
{
}

int main()
{
    vector<char *> vc = vector<char *>(); 

    fn(vc);
}
Run Code Online (Sandbox Code Playgroud)

我理解为什么vector<char*>不能转换为vector<const char*>- 类型的额外成员const char *可以添加到向量中,然后它们可以作为非const访问.但是,如果向量本身是常量,则不会发生这种情况.

我最好的猜测是,这将是无害的,但是编译器无法推断出这将是无害的.

怎么能解决这个问题?

这个问题是由C++ FQA 在这里提出的.

Dan*_*rey 11

通常,C++不允许您someclass<T>转换someclass<U>someclass可能专门用作的模板U.如何TU相关并不重要.这意味着实现以及对象布局可能不同.

遗憾的是,没有办法告诉编译器在哪些情况下布局和/或行为没有改变,应该接受演员表.我想这对于std::shared_ptr其他用例非常有用,但这不会很快发生(AFAIK).


dyp*_*dyp 6

void fn(const vector<const char*>)
Run Code Online (Sandbox Code Playgroud)

由于const函数类型的顶级限定符被删除,因此(在调用站点)相当于:

void fn(vector<const char*>)
Run Code Online (Sandbox Code Playgroud)

两者都请求传递的向量的副本,因为标准库容器遵循值语义.

你可以:

  • 通过它来调用它fn({vc.begin(), vc.end()}),请求显式转换
  • 将签名改变为例如void fn(vector<const char*> const&),参考

如果你可以修改签名fn,你可以遵循GManNickG建议并使用迭代器 /范围代替:

#include <iostream>
template<typename ConstRaIt>
void fn(ConstRaIt begin, ConstRaIt end)
{
    for(; begin != end; ++begin)
    {
        std::cout << *begin << std::endl;
    }
}

#include <vector>
int main()
{
    char arr[] = "hello world";
    std::vector<char *> vc;
    for(char& c : arr) vc.push_back(&c);

    fn(begin(vc), end(vc));
}
Run Code Online (Sandbox Code Playgroud)

这给出了漂亮的输出

hello world
ello world
llo world
lo world
o world
 world
world
orld
rld
ld
d

根本问题是传递标准库容器.如果您只需要持续访问数据,则无需知道实际的容器类型,而是可以使用模板.这将删除fn调用者使用的容器类型的耦合.

正如您所注意到的那样,允许std::vector<T*>通过a 访问是一个坏主意std::vector<const T*>&.但是,如果您不需要修改容器,则可以使用范围.

如果函数fn不能或不能作为模板,你仍然可以传递范围const char*而不是向量const char.这适用于任何保证连续存储的容器,例如原始数组,std::arrays,std::vectors和std::strings.