如果(成员)功能模板f(T &)
没有其他重载(例如,f(volatile T &&)
或template< typename T > f(T &&);
),那么T &&
就是所谓的对于某些 cv-qualified 类型T
,转发参考和U
为U &
或U
。但是对于成员函数的 cv-ref-qualifiers ,没有这样的规则。在struct S { void f() && { ; } };
中,S::f()
始终具有rvalue-reference限定符。
在通用代码中,如果所有这些函数都执行相同的操作,则避免定义4(甚至8,如果我们也考虑volatile
限定符)某些成员函数的重载将是非常有用的。
以这种方式出现的另一个问题是,在特定意义上定义*this
的有效 cv-ref-qualifier 是不可能的。以下代码不允许用户确定成员函数operator ()
的 ref-qualifier 是&&
的{{1}}。
&
但如果有上述语法,那将是非常好的。即#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))
的确切 cv-ref-qualified 类型。在我看来,将这种语法引入到 C ++ 标准的版本中并不是一个突破性的变化。但是*this
作为转发cv-ref-qualifier (它看起来像是委员会的遗漏(即核心语言工作组))。
另一个序列可以将成员函数 cv-ref-qualifier 和 cv-ref-qualified 类型&&
表示到其正文中:{ {1}},*this
等。
是否有针对此问题的提案,准备在 C ++ 17 中使用?
答案 0 :(得分:1)
是的,有这样的建议。
<强>背景强>
由于我们已经在模板函数中有转发引用,您可以简单地将您的成员函数转换为模板友元函数(并通过enable_if
保护它与F
以外的任何其他类一起使用,如果必需的)。
现在,也许你想要你真的,真的想把你的函数用作成员函数,因为你真的非常喜欢那种语法。
提案:
查找统一呼叫语法提案,例如:n4174
如果接受了类似的东西,你就可以使用第一个参数的成员函数之类的自由函数。这将涵盖您在第一条评论中链接的示例代码。不可否认,它不会涵盖operator(),但我认为与编写8个重载相比,这是一个小麻烦: - )