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

我可以为equal\u range()的返回值专门化std::begin和std::end吗?

黄元章
2023-03-14

<代码>

现在,我听到了关于专门化std::begin()std::end()的矛盾信息-有人告诉我,向std命名空间添加任何东西都会导致未定义的行为,而我也被告知,您可以提供自己的std::begin()std::end()的专门化。

这就是我现在正在做的:

namespace std
{
    template<typename Iter, typename = typename iterator_traits<Iter>::iterator_category>
    Iter begin(pair<Iter, Iter> const &p)
    {
        return p.first;
    }
    template<typename Iter, typename = typename iterator_traits<Iter>::iterator_category>
    Iter end(pair<Iter, Iter> const &p)
    {
        return p.second;
    }
}

这确实有效:http://ideone.com/wHVfkh

但我想知道,这样做有什么坏处?有更好的方法吗?

共有1个答案

子车凯泽
2023-03-14

17.6.4.2.1/1除非另有说明,否则如果C程序将声明或定义添加到命名空间std或命名空间std中的命名空间,则C程序的行为是未定义的。只有当声明依赖于用户定义的类型并且专业化满足原始模板的标准库要求且未被明确禁止时,程序才可以将任何标准库模板的模板专业化添加到命名空间std

所以是的,我相信,从技术上讲,您的代码表现出未定义的行为。也许您可以编写一个简单的类,该类在其构造函数中使用一对迭代器,并实现begin()end()方法。然后你可以写这样的东西

for (const auto& elem: as_range(equal_range(...))) {}
 类似资料:
  • 在我设法为我的类类型重载之后,我现在想要专门化它,而不是重载它,因为标准允许向名称空间添加模板专门化。下面是我的例子: 我不知道为什么它没有编译,并且我得到了一个错误:

  • 我知道了从< code>std::async返回的< code>future具有某种特殊共享状态的原因,通过这种状态,< code >等待返回的future发生在future的析构函数中。但是当我们使用< code>std::pakaged_task时,它的未来不会表现出同样的行为。要完成打包的任务,必须从< code>packaged_task显式调用< code>future对象上的< cod

  • GCC的实现销毁从返回完整表达式末尾的函数返回的数组。这是正确的吗? 该程序中的两个测试用例都显示了在可以使用该值之前执行的析构函数: 我认为这个计划应该奏效。但基本标准有点复杂。 return语句初始化返回值对象,就像它被声明一样 这将初始化给定系列初始化器中的一个临时初始化器列表及其底层数组存储,然后从第一个初始化器列表初始化另一个初始化器列表。阵列的生存期是多少?“数组的生存期与初始化器列表

  • 并行开发挺复杂的,特别是在试图用好线程和锁的过程中。如果要用到条件变量或std-atomics(一种无锁开发方式),那就更复杂了。C++0x提供了future和promise来简化任务线程间的返回值操作;同时为启动任务线程提供了packaged_task以方便操作。其中的关键点是允许2个任务间使用无(显式)锁的方式进行值传递;标准库帮你高效的做好这些了。基本思路很简单:当一个任务需要向父线程(启动

  • 标准库函数bind()和function()定义于头文件<functional>中(该头文件还包括许多其他函数对象),用于处理函数及函数参数。bind()接受一个函数(或者函数对象,或者任何你可以通过”(…)”符号调用的事物),生成一个其有某一个或多个函数参数被“绑定”或重新组织的函数对象。(译注:顾名思义,bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的。)例如: int

  • 查找表示整数为所需的最小位 为什么为值0返回0,难道不应该返回1吗。因为表示0所需的位数是1。 另外,我认为公式中的是一个偏移量