为啥 std::variant 用开始和结束迭代器编译?

Posted

技术标签:

【中文标题】为啥 std::variant 用开始和结束迭代器编译?【英文标题】:Why does a std::variant compile with begin and end iterators?为什么 std::variant 用开始和结束迭代器编译? 【发布时间】:2019-08-10 17:47:27 【问题描述】:

似乎编译器应该能够捕捉到 std::variant 没有迭代器方法的事实,但似乎我的代码编译没有问题(即使我为变体),但它在运行时崩溃(理所当然)。有人能解释一下为什么这段代码会编译吗?

注意:这不会阻止进度,因为现在我正在使用 std::visit,但很高兴知道为什么要编译。

我尝试过使用不同的变体模式,它们都可以编译。请参阅代码示例。您可以将其弹出到 cppreferences 或 Godbolt 中,它应该使用 C++17 标志或更高版本进行编译

#include <variant>
#include <string>
#include <cassert>
#include <iostream>
#include <list>
#include <map>

template<typename K, typename V>
//using var_maps = std::variant<std::map<K,V>, std::multimap<K,V> >;
//using var_maps = std::variant<std::list<int>, std::list<float> >;
using var_maps = std::variant<int, float>;

template <typename K, typename V>
void flat( const var_maps<K,V>& vmap)

    //for(auto bIter = vmap.bexxxgin(), eIter = vmap.end(); bIter != eIter;
    for(auto bIter = vmap.begin(), eIter = vmap.end(); bIter != eIter;
      bIter = vmap.upper_bound( bIter->first )  )
      

      

我最初的案例是使用地图,但它可以有效地与任何东西一起编译。此外,我可以将 begin() 随机替换为任何其他单词,它仍然可以编译。我知道正确的方法是访问。我不可避免地试图拥有一个处理地图和多地图的函数并将其转换为另一种数据结构。

谢谢!

【问题讨论】:

【参考方案1】:

您的代码可以编译,因为 begin()end() 是依赖名称 - 它们依赖于函数模板参数,因此它们的查找被推迟到 flat 模板实例化。但它永远不会被实例化!

如果您添加以下内容,您的代码将不再编译:

int main () 
     &flat<int, int>;

【讨论】:

【参考方案2】:

它“编译”是因为该函数是一个模板。此处不生成任何代码,并且在解析模板时,除了基本的语法检查之外,无法进行完整的检查。

这是因为编译器不知道var_maps&lt;K,V&gt; 是否包含begin()。可能有专业。

实例化var_maps 时会收到错误消息,即将var_maps 与具体类型KV 一起使用。

【讨论】:

我明白了,所以曾经模板化的所有方法都被推迟到实例化(无论类型如何)。我不明白的是 std::variant 永远不会有开始和结束迭代器,对吗?这什么时候会真正起作用?我认为我不能在 K 和 V 中放置任何类型,这将使​​变体具有开始和结束方法?

以上是关于为啥 std::variant 用开始和结束迭代器编译?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用循环从数组的开始迭代到结束比迭代开始到结束和结束到开始更快?

stl中vector中erase后迭代器为啥会失效

C++:为啥输出迭代器不支持比较操作?

为啥我需要另一个迭代器作为 std::copy() 中的参数?

迭代器和生成器

迭代器