C++ 标准库必须支持那些挑剔朋友是谁的类吗?

Posted

技术标签:

【中文标题】C++ 标准库必须支持那些挑剔朋友是谁的类吗?【英文标题】:Must the C++ standard library support classes that are picky about who their friends are? 【发布时间】:2015-07-18 15:09:00 【问题描述】:

这个问题最容易用一个例子来说明,所以这里是:

是否保证如下代码有效,并能正确编译和运行?

(并不是所有的实现都能正确编译它,但我想知道这是否是一个错误。)

#include <algorithm>
class Picky

    friend
        Picky *std::copy<Picky const *, Picky *>(Picky const *, Picky const *, Picky *);
    Picky &operator =(Picky const &)  return *this; 
public:
    Picky()  
;

int main()

    Picky const a;
    Picky b;
    std::copy<Picky const *, Picky *>(&a, &a + 1, &b);
    return 0;

【问题讨论】:

这实际上是在什么 stdlib 实现上编译的?我不会想到存在一个没有将std::copy 委托给某个内部助手的人。 @Praetorian:我还没有找到,但我当然可以自己写一个有效的... 如果它确实需要它来工作,这是标准中的一个缺陷。 当然可以,但是您要么陷入 SFINAE 地狱,要么就不得不放弃 memcpy 优化以及诸如此类的可复制类型。无论如何,您的问题的答案肯定是 - 不,不存在这样的保证。这有点像与std::default_delete 成为朋友并试图在unique_ptr 中使用私有析构函数来粘贴类型,这也不能保证有效。 @Praetorian 或结交make_shared 并尝试使其使用私有构造函数。 【参考方案1】:

std::copy 需要一个输出迭代器 ([algorithms.general]/p5);除其他事项外,输出迭代器要求 *r = o 有效([output.iterators],表 108) - 不仅仅是“有时有效”或“在某些情况下有效”。

因为对于Picky *p, a;*p = a 在大多数情况下无效,Picky * 不是有效的输出迭代器。


嗯,如果您可以将您的答案概括为其他事情,那就太好了 除了我给出的特定示例之外。比如说, std::vector::push_back(T const &amp;),或其他。

与成员函数成为朋友是绝对不行的,因为您甚至无法保证存在具有该签名的成员函数([member.functions]/p2,Stephan T. Lavavej 称之为"STL Implementers Can Be Sneaky Rule"):

一个实现可以声明额外的非虚拟成员函数 类中的签名:

通过将具有默认值的参数添加到成员函数签名187 [注意:实现 不能将具有默认值的参数添加到虚拟、全局或非成员函数。 — 尾注]; 将一个具有默认值的成员函数签名替换为两个或多个具有等效行为的成员函数签名;和 通过为成员函数名称添加成员函数签名。

187 因此,C++标准库中类的成员函数的地址具有未指定的类型。

【讨论】:

嗯,如果您能将您的答案概括到我给出的特定示例之外的其他事情上,那就太好了。例如,std::vector&lt;T&gt;::push_back(T const &amp;) 或其他。 有趣的编辑。这具有重要意义——你是说我什至不允许说void (std::vector&lt;int&gt;::*push_back)(int const &amp;) = &amp;std::vector&lt;int&gt;::push_back;?换句话说,我根本无法根据标准中的签名来获取成员函数的地址,因为它们可能不存在? @Mehrdad 不,你不能。该标准实际上在脚注中指出了这一点,我将其添加到引用中。 嗯,C++11 中的 std::swap 怎么样?您可以将T::T(T &amp;&amp;)T &amp;T::operator =(T &amp;&amp;) 设为私有并将std::swap&lt;T&gt; 声明为朋友并期望它起作用吗?这既不是成员函数,也不需要迭代器。 @Mehrdad 不;它需要MoveConstructibleMoveAssignable,并且两者都要求相关构造无条件有效。【参考方案2】:

如果std::copy() 不调用任何其他非友元函数,代码可能会编译,但我还没有遇到任何这样的实现。并且标准中没有要求std::copy()如何达到要求的效果。

但是,它确实需要一个有效且可访问的赋值运算符。

【讨论】:

以上是关于C++ 标准库必须支持那些挑剔朋友是谁的类吗?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中有标准的日期/时间类吗?

C++--标准库 字符串类

详解C++标准库<sstream>中的类stringstream,并利用它实现OpenCV下的图片批量读取

C++ vector类型要点总结(以及各种algorithm算法函数)

C++标准库和标准模板库

C++标准库与STL的关系