当前位置: 首页 > 知识库问答 >
问题:

基于范围的For Loop和ADL

卫子平
2023-03-14

这是从2011年开始对这个问题的扩展:基于范围的for loops和ADL

使用Visual Studio 2015,我无法使用参数依赖查找(ADL)为自定义容器创建基于范围的for循环

我在下面用一个自定义容器做了一个非常简单的测试用例:

#include <vector>

namespace Foo
{
    template <typename T>
    class Container
    {
    public:

        std::vector<T> values;
    };
}

template <typename T>
typename std::vector<T>::iterator begin(Foo::Container<T>& foo)
{
    return foo.values.begin();
}

template <typename T>
typename std::vector<T>::iterator end(Foo::Container<T>& foo)
{
    return foo.values.end();
}

使用此容器和ADL,以下测试可以很好地编译:

int main(int argc, char* argv[])
{
    Foo::Container<int> values;

    for (auto it = begin(values); it != end(values); ++it)
    {
        ...
    }

    return 0;
}

这是应该的。我不确定ADL是否在这里得到了利用,但无论如何,它是有意义的。根据MSDN文档,我们有:

请记住以下事实:

>

识别具有的容器。begin()和。结束()。

对其他任何内容使用与参数相关的查找start()和end()。

根据我对ADL的理解以及上述文档,还应汇编以下内容:

int main(int argc, char* argv[])
{
    Foo::Container<int> values;

    for (auto value : values)
    {
        ...
    }

    return 0;
}

但事实并非如此。相反,我得到了以下错误:

error C3312: no callable 'begin' function found for type 'Foo::Container<int>'
error C3312: no callable 'end' function found for type 'Foo::Container<int>'

那么这是怎么回事?是我对ADL的解释不正确,还是这是MSVC 14.0编译器的错误?

共有1个答案

程皓轩
2023-03-14

您必须将startend都放入Foo命名空间才能让ADL工作。这是因为ADL会查看相应参数的命名空间以搜索开始end的定义。

namespace Foo
{
    template <typename T>
    class Container
    {
    public:

        std::vector<T> values;
    };

    template <typename T>
    typename std::vector<T>::iterator begin(Foo::Container<T>& foo)
    {
        return foo.values.begin();
    }

    template <typename T>
    typename std::vector<T>::iterator end(Foo::Container<T>& foo)
    {
        return foo.values.end();
    }
}

UPD:不考虑全局命名空间中的开始结束的原因是更新后的标准说开始结束在关联的命名空间中查找,但不执行普通的不合格查找。这是标准(http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442)中错误修复的结果。

 类似资料:
  • 问题内容: 我如何让SQL重复一些基于集合的操作任意次数而不会循环?如何让SQL对一定范围的数字执行运算?我基本上是在寻找一种基于集合的for循环的方法。 我知道我可以创建一个包含整数(例如1到1000)的小表,然后将其用于该范围内的范围操作。 例如,如果我有该表,则可以选择查找数字100-200的总和,如下所示: 有任何想法吗?我有点在寻找适用于T-SQL的东西,但是任何平台都可以。 问题答案:

  • 由于valgrind中出现了一些分段错误和警告,我发现这段代码不正确,并且在for range循环中有一些悬而未决的引用。 看起来好像开始和结束是从一个临时循环中提取的,并且在循环中丢失了。 当然,一种方法是 然而,我想知道为什么for(auto e:f()[5])是一个错误,以及是否有更好的方法或某种方法来设计f,甚至容器(

  • 在std::unordered_映射上运行基于范围的for循环时,循环变量的类型似乎不使用引用类型: MSVC 2017、gcc 8.2和clang 7.0.0都在这里报告了一个失败的断言。与std::vector相反,它的断言不会失败,正如人们所期望的那样: 然而,在MSVC 2017和gcc 8.2上,修改局部变量r的循环将产生明显的副作用: 例如,此程序将打印(忽略订单): 我遗漏了什么?尽

  • 我对C很陌生,现在就在做中学习。在课堂材料中,我有以下功能: 几分钟前,我像这样使用了普通for循环:

  • 在临时范围上基于范围的for循环中,Barry提到以下内容不受被破坏的临时对象的影响,我测试的成员v确实存在于for循环的整个循环中(因为在for循环的整个循环中没有调用析构函数X)。解释是什么?

  • 问题内容: 我阅读了有关sessionStorage和localStorage的一些文档,但是我不明白范围是什么:域,特定页面? 并且如果在上述每个页面上运行(idvalue是查询字符串中的值): 我最终会存储3个不同的值,还是两个值会互相覆盖? 问题答案: 这些值将互相覆盖。每个密钥名称对对于协议和域而言都是唯一的,而与路径无关。 可以通过属性更改受影响的域。 -> 可以(子域) -> 不可能