【问题标题】:Why std::sort doesn't accept Compare classes declared within a function为什么 std::sort 不接受在函数中声明的比较类
【发布时间】:2013-01-13 19:06:07
【问题描述】:

我在工作,在一个函数中编写比较器(稍后移动,当我决定哪里最好时),并注意到了这个特殊性。我想了一会儿,意识到我不明白为什么如果我使用内部比较器,代码将无法编译,但外部比较器很好。

有什么解释吗?

快速测试工具:

#include <iostream>
#include <vector>
#include <algorithm>

class CompareMe
{
 public:
    CompareMe(int in) : toCompare(in){}
    int toCompare;
};

class Comparators
{
public:
    bool operator()(CompareMe * first, CompareMe * second)
    {
        return first->toCompare < second->toCompare;
    }
};

class ComparatorsOuter : public Comparators{};

int main()
{
    class ComparatorsInner : public Comparators{};

    std::vector<CompareMe *> compares;
    compares.push_back(new CompareMe(0));
    compares.push_back(new CompareMe(1234));
    compares.push_back(new CompareMe(163));
    compares.push_back(new CompareMe(6));
    compares.push_back(new CompareMe(12));

    //This works, and properly sorts the array
    ComparatorsOuter comparator;
    std::sort(compares.begin(), compares.end(), comparator);

    //Uncomment out the sort below and it will not compile.
    ComparatorsInner comparatorInner;
    //std::sort(compares.begin(), compares.end(), comparatorInner);

    std::vector<CompareMe *>::iterator it;
    for(it = compares.begin(); it != compares.end(); ++it)
    {
        std::cout << (*it)->toCompare << std::endl;
    }
}

错误:没有匹配的函数调用 'sort(__gnu_cxx::__normal_iterator&lt;CompareMe**, std::vector&lt;CompareMe*, std::allocator&lt;CompareMe*&gt; &gt; &gt;, __gnu_cxx::__normal_iterator&lt;CompareMe**, std::vector&lt;CompareMe*, std::allocator&lt;CompareMe*&gt; &gt; &gt;, main()::ComparitorInner&amp;)'

【问题讨论】:

  • breaks down 是什么意思?也许您使用的是较旧的编译器?
  • 我的意思是,它不能编译。我将进行编辑以澄清。
  • 顺便说一句,它的拼写是“比较器”。
  • 模板参数必须有全局链接,因为结果有它。
  • @jthill:相反,他们过去没有很好的理由需要全局链接,现在不需要了。

标签: c++


【解决方案1】:

在 C++03 中,模板参数不能有内部链接:

[C++03: 14.6.4.2/1]:对于依赖于模板参数的函数调用,如果函数名是unqualified-id而不是template-id,则候选函数使用通常的查找规则(3.4.1、3.4.2)找到,除了:

  • 对于使用非限定名称查找的部分查找 (3.4.1),只能找到具有来自模板定义上下文的外部链接的函数声明
  • 对于使用关联命名空间 (3.4.2) 的查找部分,只能找到在模板定义上下文或模板实例化上下文中找到的具有外部链接的函数声明。

[..]

这已在 C++11 中更改(问题 #561: "Internal linkage functions in dependent name lookup"):

[C++11: C.2.6]: 14.6.4.2
更改:允许对具有内部链接的函数进行依赖调用
理由:过度约束,简化重载决议规则。

导致:

[C++11: 14.6.4.2/1]: 对于依赖于模板参数的函数调用,使用通常的查找规则(3.4.1、3.4.2、3.4.3)找到候选函数,除了:

  • 对于使用非限定名称查找 (3.4.1) 或限定名称查找 (3.4.3) 的查找部分,只能找到来自模板定义上下文的函数声明。
  • 对于使用关联命名空间 (3.4.2) 的查找部分,只能找到在模板定义上下文或模板实例化上下文中找到的函数声明。

[..]

(找出缺少的“与外部链接” 限定条件。)

由于您的main()::ComparitorInner&amp; 具有内部链接,并且std::sort 的实例化需要此类型作为模板参数(尽管是推导的),因此您的代码仅在 C++11 中有效。

【讨论】:

  • 不错的答案,请参阅number 7 here 显然clang 允许在 C++03 模式下执行此操作并发出警告,这有点令人惊讶。
  • @ShafikYaghmour:很好的回答你!
  • 我不打算回答这么长。
  • 嗨,我知道这是一个旧答案,但您引用了 ADL/Koenig 查找标准的部分内容,这不适用于此处。正确的部分是 14.3.1,它只是不允许将本地类型用作模板参数。
【解决方案2】:

您的代码在 C++11 中很好;在 C++03 中使用局部类型作为模板参数有一个限制。

【讨论】:

  • 太棒了,这是我以前从未遇到过的限制。编译器错误:没有匹配函数调用'sort(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, main()::ComparitorInner&)' 现在很有意义!
猜你喜欢
  • 1970-01-01
  • 2022-01-18
  • 2019-10-23
  • 1970-01-01
  • 2021-11-19
  • 1970-01-01
相关资源
最近更新 更多