繁体   English   中英

&#39;模板的专业化<class _Tp>不同命名空间中的 struct std::less&#39;

[英]Specialization of 'template<class _Tp> struct std::less' in different namespace

我专门针对数据类型使用“较少”(谓词)。

代码如下所示:

template<>
struct std::less<DateTimeKey>
{
   bool operator()(const DateTimeKey& k1, const DateTimeKey& k2) const
   {
      // Some code ...
   }
}

编译时(在 Ubuntu 9.10 上为 g++ 4.4.1),出现错误:

不同命名空间中“模板结构 std::less”的专业化

我做了一些研究,发现有一个“解决方法”,它涉及将专业化包装在 std 命名空间中 - 即将代码更改为:

namespace std {
template<>
struct less<DateTimeKey>
{
   bool operator()(const DateTimeKey& k1, const DateTimeKey& k2) const
   {
      // Some code ...
   }
}
}

这确实关闭了编译器。 然而,这个解决方案来自一个 5 岁的孩子(“伟大的”维克多·巴扎罗夫(Victor Bazarof)同样[双关语意外])。 此修复程序是否仍然可行,或者是否有更好的方法来解决此问题,或者“旧方法”仍然有效?

这仍然是这样做的方法。 不幸的是,您不能像在类中那样在名称空间中声明或定义函数:您需要将它们实际包装在名称空间块中。

如果您需要专门化标准算法,您可以在 std 命名空间中进行。 根据标准,这是唯一允许您在该命名空间内执行的操作。

[lib.reserved.names]/1

除非另有说明,否则 C++ 程序向命名空间 std 或命名空间 std 内的命名空间添加声明或定义是未定义的。 程序可以将任何标准库模板的模板特化添加到命名空间 std。 标准库模板的这种特化(完全或部分)会导致未定义的行为,除非声明依赖于用户定义的外部链接名称,并且除非特化满足原始模板的标准库要求

现在,问题是您是否真的想要专门化std::less 请注意, std::less将调用为您的类型定义的比较运算符,因此您可以提供该操作而不是专门化模板。

为您的特定类型专门化std::less的问题是,如果您提供的操作与operator<为您的类型执行的operator<不同,则会引起混淆。 如果它们执行相同的操作,只需保留默认的std::less定义而无需专门化。

如果您不想提供比较运算符,但仍想在关联容器或需要比较器的算法中使用该类型,则可以使用其他名称提供外部比较函子,以免混淆其他读者(以及您自己)未来)。

你为什么要这样做?

std::less存在仅用于两个目的:

  1. 给运算符 < 命名,允许它作为函子传递
  2. 明确允许比较不在同一个数组中的两个指针(如果使用原始指针,这在技术上是非法的)

用户没有理由重载它 - 重载operator<或使用自定义比较器函数。

有一些标准算法可以被合理地特化std::swap是一个很好的例子——为此你需要在命名空间 std 中声明特化。

less 函子不必在std命名空间中。 所以

struct A
{
    A(int _v=0):v(_v){}
    int v;
};


template<>  struct less<A>
{
    bool operator()(const A& k1, const A& k2) const
    {
        return k1.v < k2.v;
    }
};


std::map<A,int> m;
m[A(1)] = 1;
m[A(2)] = 2;

按预期工作。 (调用您刚刚创建的函子)。

我想您已经知道了,但是您可以编写自己的 operator<(k1,k2),这就是默认的 less 函子要查找的内容。

bool operator<(const DateTimeKey & k1, const DateTimeKey & k2)
{
//your code...
}

即使其他人已经回答了这个问题,并回答了如何专门化std::less (通过将它们包装在命名空间块中)和正确的方法(重载operator < )。

但是, C++现在允许(在C++11 )按照您在第一个示例中所做的方式进行规范。

显式特化应在包含特化模板的命名空间中声明。 其 declarator-id 未限定的显式特化应在模板的最近封闭命名空间中声明,或者,如果命名空间是内联的 (7.3.1),则应在其封闭命名空间集中的任何命名空间中声明。 这样的声明也可以是定义。 如果声明不是定义,则可以稍后定义特化(7.3.1.2)。

我在我的Ubuntu机器上用g++ (8.3.0)尝试了以下代码。

#include <iostream>

#include <map>
#include <string>
#include <algorithm>


class myType {

public:
    myType(int in): i_(in) { }

    int i_;
};

template <>
struct std::less<myType>  {
    bool operator()(const myType& a, const myType& b) const
    {
        return a.i_ < b.i_;
    }
};


int main(int argc, char *argv[])
{
    std::map<myType, std::string> vector = { { 1, "1"}, { 2, "2"}, { 3, "3"}, { 0, "0" } };

    for (auto& i: vector)
        std::cout << i.first.i_ << std::endl;
    return 0;
}

上面的代码是用

g++ --std=c++11 compare.cpp -Wall 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM