为什么 std::variant 使用开始和结束迭代器进行编译?

Why does a std::variant compile with begin and end iterators?

似乎编译器应该能够捕捉到 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() 替换为任何其他单词,它仍然可以编译。我知道正确的方法是访问。我不可避免地要尝试使用一个函数来处理 map 和 multimap 并将其转换为另一种数据结构。

谢谢!

它"compiles"因为函数是一个模板。这里没有生成代码,除了基本的语法检查之外,在解析模板时无法进行完整的检查。

这是因为编译器不知道var_maps<K,V>是否包含begin()。可能会有专业化。

实例化 var_maps 时,您将收到错误消息,即使用具有具体类型 KVvar_maps

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

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

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