C++ 是否可以铸造一对<;关键、价值>;一双<;常量键,值>;?

C++ 是否可以铸造一对<;关键、价值>;一双<;常量键,值>;?,c++,stl,constants,const-cast,std-pair,C++,Stl,Constants,Const Cast,Std Pair,所以我有一个智能迭代器来模拟map const_迭代器,它需要在内部构建返回类型。显然,我希望在迭代器类中存储一个对(因为我需要修改它),但同时我希望解引用函数呈现一个对(实际上它将分别是常量对&和常量对*)。到目前为止,我提出的唯一解决方案是每次更改迭代器类指向的值时动态分配一个新的对。不用说,这不是一个好的解决方案 我还尝试了*const_cast(&value),其中value声明为pair 任何帮助都将不胜感激(知道这是不可能的) 编辑 出于好奇:我最终在迭代器类中存储了一个对p。为了更

所以我有一个智能迭代器来模拟map const_迭代器,它需要在内部构建返回类型。显然,我希望在迭代器类中存储一个
(因为我需要修改它),但同时我希望解引用函数呈现一个
(实际上它将分别是
常量对&
常量对*
)。到目前为止,我提出的唯一解决方案是每次更改迭代器类指向的值时动态分配一个新的对。不用说,这不是一个好的解决方案

我还尝试了
*const_cast(&value)
,其中
value
声明为
pair

任何帮助都将不胜感激(知道这是不可能的)

编辑

出于好奇:我最终在迭代器类中存储了一个
对p
。为了更改该对,我将根据基础迭代器(
map::const_iterator it
)分别更改这两个元素,
const_cast
对键进行加密,以便对其进行更改,如下所示:

*const_cast<Key*>(&p.first) = it->first;
p.second = it->second;
*const_cast(&p.first)=it->first;
p、 秒=它->秒;
这不是一个我非常满意的解决方案,但它完成了任务,而且解引用方法也很满意,因为我存储了一些正确类型的内容,它们可以引用。

是的

std::pair<int, double> p(1,2);
std::pair<const int, double> q = p;   // no problem

//q.first = 8;  // error
q.second = 9;

int b; double d;
std::pair<int &, double &> s(b,d);
std::pair<int const &, double &> t = s;  // also fine
std::对p(1,2);
标准::对q=p;//没问题
//q、 第一个=8;//错误
q、 秒=9;
int b;双d;
std::对s(b,d);
std::对t=s;//也很好
您可以将类型为
pair
的值转换为
pair

然而,仔细阅读这个问题,你实际上是在问,给定一个
,你是否可以创建一个指向同一对象的
的指针或引用

答案是否定的——只有在对象类型继承自被引用类型的情况下,指向一种类型的引用或指针才能引用另一种类型的对象


一种可能是返回一对引用,
pair
,它是从您希望引用的对创建的。

正如Kerrek SB指出的,您可以从
std::pair
构造
std::pair
。然而,您最初的问题意味着您希望避免在每次取消引用迭代器时构造std::pair对象

不幸的是,没有一个好的方法来做到这一点。您可能需要构造pair对象并将其实际存储在某个位置,特别是对于操作符->。否则,您必须能够让映射实际存储
pair
,才能从迭代器返回对它的引用/指针。基本上,为了返回引用/指针,它必须以这种形式存储在某个地方:它不能是临时的


避免const_cast。这只是要求在使用它以这种方式强制转换pair时使用未定义的行为,即使它可能经常工作。

我遇到了完全相同的问题。我的解决方案是创建一个新的映射对象作为迭代器类的一部分,然后向其中添加上游映射类中缺少的成员,并将引用返回给它的成员。效率不是很高,但很有效

您的解决方案有两个问题:

  • 使用const_cast分配const变量是未定义的行为。编译器优化可能会产生奇怪的结果
  • 任何新的取消引用都将使以前取消引用的结果无效。不应该这样做。因此,根据迭代器的使用情况,它也可能产生奇怪的结果
  • 这可以通过以下方法解决,并且它纯粹是一个编译时指令

    std::pair<int, double> p1 = { 1, 2.3 };
    auto& p2 = reinterpret_cast<std::pair<const int, double>&>(p1);    // type of p2 is pair<const int, double>&
    
    //++(p2.first);    // error: expression must be a modifiable lvalue
    ++(p1.first);
    assert(p2.first == 2);
    
    

    很难相信你会不遗余力地发表这篇小文章而不去尝试:
    std::pair p(1,2);标准::对q=p;//很好
    @Kerrek SB:我认为你忽略了Op问题的一个重要部分。他希望避免每次调用自定义迭代器的解引用/成员选择操作符时构造新的pair对象。这在operator->中变得尤为重要,因为这意味着他的迭代器可能需要存储一个成员对,并在每次调用函数或迭代器递增/递减时复制到该成员对中。@KerrekSB:谢谢你给我上了一堂有问题的课。我将努力在将来更清楚地表达自己。我很好奇
    std::map
    是如何做到的,因为它有
    extract()
    。使用Apple的叮当声STL,节点持有一个
    std::pair
    。该节点有一个
    \uuuu ref()
    ,它返回一个
    std::pair
    ,它通过
    const\u cast
    键生成该对。虽然说
    node\u handle
    是UB“如果std::pair或std::pair存在用户定义的std::pair专门化”(我怀疑为整对的转换腾出空间),但我的实现似乎避免了这一点。谢谢,我将看看这对引用解决方案是否能解决我的特定问题(感谢您的仔细阅读,我以后会尽量更清楚地表达自己)。在我的特殊情况下,这将导致返回对临时的引用,而该引用无法编译。@MarkusSaers:给定您的
    对p
    ,您可以返回
    对(p.first,p.second)
    ,它不会创建任何临时对象。但在我的例子中,没有上游映射对象(它是一个自定义容器类,不包含可引用的std::pair元素。不过,您可以在每次迭代器取消引用时以某种方式创建内部临时std::pair元素,并在迭代器实例销毁时销毁它们。
    using srcType = std::pair<Key, Value>;
    using tarType = std::pair<const Key, Value>;
    
    static_assert(
        offsetof(srcType, first) == offsetof(tarType, first)
     && offsetof(srcType, second) == offsetof(tarType, second)
    );