其他分享
首页 > 其他分享> > c – 什么是自定义点对象以及如何使用它们?

c – 什么是自定义点对象以及如何使用它们?

作者:互联网

c标准的最后一个草案引入了所谓的“定制点对象”([customization.point.object]),
它们被范围库广泛使用.

我似乎明白,他们提供了一种编写开始,交换,数据等自定义版本的方法
由ADL的标准库发现.那是对的吗?

这与用户如何定义例如过载的先前实践有何不同?从她自己的类型开始
命名空间?特别是,他们为什么反对?

解决方法:

What are customization point objects?

它们是命名空间std中的函数对象实例,它们实现两个目标:首先对参数无条件地触发(设想)类型要求,然后在命名空间std或通过ADL调度到正确的函数.

In particular, why are they objects?

这是绕过第二个查找阶段所必需的,该阶段将通过ADL直接引入用户提供的功能(这应该被设计推迟).请参阅下面的更多细节.

… and how to use them?

开发应用程序时:主要不是.这是一个标准的库功能,它将概念检查添加到未来的定制点,希望如此产生,例如,当您搞乱模板实例化时,在明确的错误消息中.但是,通过对此类自定义点的合格调用,您可以直接使用它.这是一个符合设计的虚构std :: customization_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等.

说明(N4381的摘要)

让我试着消化标准中这一部分背后的提议.标准库使用的“经典”自定义点有两个问题.

>他们很容易出错.例如,在通用代码中交换对象应该看起来像这样

template<class T> void f(T& t1, T& t2)
{
    using std::swap;
    swap(t1, t2);
}

但是对std :: swap(t1,t2)进行合格调用过于简单 – 用户提供的
交换永远不会被调用(见
N4381,动机和范围)
>更严重的是,没有办法将(受限制的)约束集中在传递给这些用户提供的函数的类型上(这也是为什么这个主题在C 20中获得重要性的原因).再次
N4381

Suppose that a future version of std::begin requires that its argument model a Range concept.
Adding such a constraint would have no effect on code that uses std::begin idiomatically:

using std::begin;

begin(a);

If the call to begin dispatches to a user-defined overload, then the constraint on std::begin
has been bypassed.

提案中描述的解决方案可以缓解这两个问题
通过类似下面的方法,std :: begin的虚构实现.

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{}; 
}

首先,打电话给例如std :: begin(someObject)总是绕过std :: __ detail :: __ begin_fn,
这是所希望的.对于不合格的电话会发生什么,我再次参考原始论文:

In the case that begin is called unqualified after bringing std::begin into scope, the situation
is different. In the first phase of lookup, the name begin will resolve to the global object
std::begin. Since lookup has found an object and not a function, the second phase of lookup is not
performed. In other words, if std::begin is an object, then using std::begin; begin(a); is
equivalent to std::begin(a); which, as we’ve already seen, does argument-dependent lookup on the
users’ behalf.

这样,概念检查可以在std命名空间中的函数对象中执行,
在ADL调用用户提供的函数之前执行.没有办法绕过这个.

标签:c20,c
来源: https://codeday.me/bug/20191004/1852744.html