Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么是自定义点对象以及如何使用它们? C++标准的最后一稿介绍了所谓的“定制点对象”() 范围库广泛使用的_C++_C++20 - Fatal编程技术网

什么是自定义点对象以及如何使用它们? C++标准的最后一稿介绍了所谓的“定制点对象”() 范围库广泛使用的

什么是自定义点对象以及如何使用它们? C++标准的最后一稿介绍了所谓的“定制点对象”() 范围库广泛使用的,c++,c++20,C++,C++20,我似乎明白,它们提供了一种编写自定义版本的开始、交换、数据等的方法,这些都是 由ADL的标准库找到。对吗 这与以前的做法有什么不同?以前的做法是,用户为自己的类型定义重载,例如,begin 名称空间?特别是,为什么它们是对象 什么是自定义点对象 它们是命名空间std中的函数对象实例,实现了两个目标:首先无条件触发(概念化)参数的类型要求,然后分派到命名空间std中的正确函数或通过ADL 特别是,为什么它们是对象 这对于绕过第二个查找阶段是必要的,该阶段将通过ADL直接引入用户提供的功能(这应该由

我似乎明白,它们提供了一种编写自定义版本的
开始
交换
数据
等的方法,这些都是 由ADL的标准库找到。对吗

这与以前的做法有什么不同?以前的做法是,用户为自己的类型定义重载,例如,
begin
名称空间?特别是,为什么它们是对象

什么是自定义点对象

它们是命名空间
std
中的函数对象实例,实现了两个目标:首先无条件触发(概念化)参数的类型要求,然后分派到命名空间
std
中的正确函数或通过ADL

特别是,为什么它们是对象

这对于绕过第二个查找阶段是必要的,该阶段将通过ADL直接引入用户提供的功能(这应该由设计推迟)。有关更多详细信息,请参见下文

。。。如何使用它们

在开发应用程序时:您基本上不需要。这是一个标准的库功能,它将为将来的定制点添加概念检查,希望在模板实例化出错时产生清晰的错误消息。但是,通过对此类定制点的限定调用,您可以直接使用它。下面是一个虚构的
std::customization\u point
对象的示例,该对象依附于设计:

namespace a {
    struct A {};
    // Knows what to do with the argument, but doesn't check type requirements:
    void customization_point(const A&);
}

// Does concept checking, then calls a::customization_point via ADL:
std::customization_point(a::A{});
这在当前的情况下是不可能的,例如
std::swap
std::begin

解释(概述) 让我试着理解一下标准中这一部分背后的建议。标准库使用的“经典”定制点存在两个问题

  • 他们很容易出错。例如,在通用代码中交换对象应该是这样的

    template<class T> void f(T& t1, T& t2)
    {
        using std::swap;
        swap(t1, t2);
    }
    
    首先,对例如
    std::begin(someObject)
    的限定调用始终通过
    std::\uuu detail::\uuu begin\fn绕行,
    这是需要的。对于一个不合格的电话,我再次参考原始文件:

    在将
    std::begin
    引入范围后调用begin的情况下,情况 这是不同的。在查找的第一阶段,名称begin将解析为全局对象
    std::begin
    。由于查找找到的是对象而不是函数,因此查找的第二阶段不是 表演。换句话说,如果
    std::begin
    是一个对象,那么
    使用std::begin;开始(a)是
    相当于
    std::begin(a)我们已经看到,它在
    代表用户

    这样,可以在
    std
    命名空间中的函数对象内执行概念检查, 在执行对用户提供功能的ADL调用之前。这是无法避免的。

    “自定义点对象”有点用词不当。许多——可能是大多数——实际上并不是定制点

    ranges::begin
    ranges::end
    、和
    ranges::swap
    等都是“真正的”CPO。调用其中一个会导致进行一些复杂的元编程,以确定是否有有效的自定义
    begin
    end
    swap
    进行调用,或者是否应该使用默认实现,或者调用是否应该是格式错误的(以SFINAE友好的方式)。由于许多库概念是根据有效的CPO调用定义的(如
    范围
    可交换
    ),因此正确约束的泛型代码必须使用此类CPO。当然,如果您知道具体类型以及从中获取迭代器的另一种方法,请放心

    ranges::cbegin
    这样的东西是没有“CP”部分的CPO。他们总是做默认的事情,所以这不是什么定制点。类似地,范围适配器对象是CPO,但它们没有任何可定制的特性。将它们分类为CPO更多的是一致性(对于
    cbegin
    )或规范便利性(适配器)


    最后,像
    ranges::所有的
    都是准cpo或niebloid。它们被指定为函数模板,具有特殊的神奇ADL阻塞属性和weasel措辞,以允许它们作为函数对象实现。这主要是为了防止当
    std::ranges
    中的受约束算法被称为unqualified时,ADL在命名空间
    std
    中拾取未受约束的重载。因为
    std::ranges
    算法接受迭代器哨兵对,所以它通常没有其
    std
    对应的算法那么专业化,因此会丢失重载解析。

    它不应该是
    constepr auto begin=\uu detail::\uu begin\u fn{}
    在匿名名称空间中?请注意,ODR的诡计是由C++17内联变量实现的。现在
    内联constexpr\uuuuu详细信息::\uuuu begin\fn begin{}应该足够了。这是标准库的一个实现细节还是用户必须注意自定义点?在
    std::
    中没有直接的CPO,IIRC。@Peregring lk我也这么认为,否则会破坏向后兼容性。
    ranges::data
    ranges::size
    ,和
    范围::空
    ?它们是“真实的”CPO吗?是的,它们实际上是可定制的。
    namespace std {
        namespace __detail {
            /* Classical definitions of function templates "begin" for
               raw arrays and ranges... */
    
            struct __begin_fn {
                /* Call operator template that performs concept checking and
                 * invokes begin(arg). This is the heart of the technique.
                 * Everyting from above is already in the __detail scope, but
                 * ADL is triggered, too. */
    
            };
        }
    
        /* Thanks to @cpplearner for pointing out that the global
           function object will be an inline variable: */
        inline constexpr __detail::__begin_fn begin{}; 
    }