成员函数的cv-ref限定符转发

11
如果没有其他重载(例如f(T &)f(volatile T &&))(成员)函数模板template< typename T > f(T &&);,那么T &&被称为转发引用,而TU,或者对于某些cv限定类型UT &。但是对于成员函数的cv-ref限定符,没有这样的规则。在struct S { void f() && { ; } };中,S::f()总是具有rvalue引用限定符。

在通用代码中,如果所有重载函数都执行相同的操作,则避免定义4个(甚至8个,如果我们还考虑volatile限定符)某个成员函数的重载函数将非常有用。

另一个问题是,在这种方式下无法定义*this的有效cv-ref限定符。以下代码不允许确定成员函数operator ()ref限定符&&还是&

#include <type_traits>
#include <utility>
#include <iostream>

#include <cstdlib>

#define P \
{                                                                       \
    using this_ref = decltype((*this));                                 \
    using this_type = std::remove_reference_t< this_ref >;              \
    std::cout << qual() << ' '                                          \
              << (std::is_volatile< this_type >{} ? "volatile " : "")   \
              << (std::is_const< this_type >{} ? "const " : "")         \
              << (std::is_lvalue_reference< this_ref >{} ? "&" : "&&")  \
              << std::endl;                                             \
}

struct F
{
    constexpr int qual() & { return 0; }
    constexpr int qual() const & { return 1; }
    constexpr int qual() && { return 2; }
    constexpr int qual() const && { return 3; }
    constexpr int qual() volatile & { return 4; }
    constexpr int qual() volatile const & { return 5; }
    constexpr int qual() volatile && { return 6; }
    constexpr int qual() volatile const && { return 7; }
    void operator () () & P
    void operator () () const & P
    void operator () () && P
    void operator () () const && P
    void operator () () volatile & P
    void operator () () volatile const & P
    void operator () () volatile && P
    void operator () () volatile const && P
};

int
main()
{
    {
        F v;
        F const c{};
        v();
        c();
        std::move(v)();
        std::move(c)();
    }
    {
        volatile F v;
        volatile F const c{};
        v();
        c();
        std::move(v)();
        std::move(c)();
    }
    return EXIT_SUCCESS;
}

但如果存在上述语法,那将会非常好。即decltype((*this))表示*this的确切cv-ref-qualified类型。在我看来,引入这样的语法到C++标准的即将推出的版本中并不会产生破坏性变化。但是,&&作为forwarding cv-ref-qualifier是可以的(而且它看起来像是委员会遗漏了的事情(即核心语言工作组))。
另一个序列可以用来表示成员函数cv-ref-qualifiercv-ref-qualified类型,即auto &&decltype(&&)等。
关于这个问题,是否有关于在C++17中使用的提案呢?

1
关于编程上如何通过程序判断成员是否合格,例如 &&&,可能值得单独提出一个问题。例如,这与前向引用并不相关(相反),而您正在使用它来比较我认为是主要问题的内容。 - Luc Danton
@LucDanton 在上下文中,问题是紧密相连的。 - Tomilov Anatoliy
1
我不明白。这里尝试总结一下:“为什么转发引用允许在cv-ref限定符上进行抽象,而对于隐式参数则不可能?”一方面,“代码能否或将会找出应用于隐式参数的cv-ref限定符?”另一方面。 - Luc Danton
@LucDanton如果有一个单一的“forwarding”cv-ref-qualified函数,那么代码组成部分应该知道在每个特定实例化期间选择了哪个重载,不是吗? - Tomilov Anatoliy
你现在正在问第三个问题吗? - Luc Danton
在我看来-不是。但是我的知识体系可能与你的不同。因此,我的问题观念也可能不同。 - Tomilov Anatoliy
1个回答

1

是的,有这样的提议。

背景:

由于模板函数中已经有了转发引用,因此您可以将成员函数简单地转换为模板友元函数(如果需要,可以通过enable_if保护它,以防止与F以外的任何类一起使用)。

现在,也许您真的很想将函数用作成员函数,因为您真的非常喜欢那种语法。

提议:

查找统一调用语法提议,例如:n4174

如果这样的提议被接受,则您将能够像第一个参数的成员函数一样使用自由函数。这将涵盖您在第一条评论中链接的示例代码。不可否认,它无法涵盖operator(),但与编写8个重载相比,我认为这只是一个小麻烦 :-)


成员函数相比全局函数的好处不仅在于语法,特别是当类是模板且您正在处理重载时。在全局作用域中,您必须以某种方式区分类作用域中的 A<T>::f(T)A<T>::f(U) - Vahagn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接