在不同的命名空间</class>中'template <class _tp =“”> struct std :: less'的专业化

时间:2010-02-17 16:19:47

标签: c++

我专注于数据类型的'less'(谓词)。

代码如下所示:

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

编译时(在Ubuntu 9.10上使用g ++ 4.4.1),我收到错误:

不同命名空间中“template struct std :: less”的专业化

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

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

确实会关闭编译器。然而,这个解决方案来自一个5岁的职位(由'伟大的'Victor Bazarof而不是[双关语])。这个修复方法还有很长的路要走,还是有更好的方法来解决这个问题,还是“老方法”仍然有效?

5 个答案:

答案 0 :(得分:24)

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

答案 1 :(得分:23)

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

  

[lib.reserved.names] / 1

     

对于C ++程序来说,它是未定义的   添加声明或定义   命名空间std或命名空间   命名空间std除非另有说明   指定。程序可以添加模板   任何标准的专业化   库模板到命名空间std。   这样的专业化(完整或   部分)标准库   模板导致未定义的行为   除非声明取决于a   用户定义的外部链接名称   除非专业化会议   标准库要求   原始模板

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

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

如果您不想提供比较运算符,但仍希望在关联容器中使用类型或使用需要比较器的算法,则可以通过其他名称提供外部比较仿函数,这不会混淆其他读者(和你自己在未来的某个地方。)

答案 2 :(得分:3)

较少的仿函数不必位于 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;

按预期工作。 (调用刚创建的仿函数)。

我猜你已经知道了,但是你可以编写自己的运算符&lt;(k1,k2),这是默认的较少的函子所寻找的。

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

答案 3 :(得分:3)

你为什么要这样做?

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

  1. 为运营商&lt;提供名称,允许将其作为仿函数传递
  2. 明确允许比较不在同一个数组中的两个指针(如果用原始指针完成,这在技术上是非法的)
  3. 用户没有理由重载它 - 重载operator<或使用自定义比较器功能。

    有std算法可以明智地专门化 - std::swap是一个很好的例子 - 为此你需要在命名空间std中声明特化。

答案 4 :(得分:0)

即使其他人回答了该问题,也提供了有关如何专门化std::less的答案(通过将它们包装在名称空间块中)以及正确的方法(重载operator <)。 / p>

但是,C++现在允许(在C++11中)以您在第一个示例中的方式为特色。

  

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

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

#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