我最近注意到一个关于 C++23推导此功能的奇怪问题。
S假设我们有一个带有简单转换运算符的结构:
struct S {
operator int() { return 42; }
};
int i = S{};
Run Code Online (Sandbox Code Playgroud)
由于42是 类型int,我们可以将转换运算符的返回类型指定为auto,例如:
struct S {
operator auto() { return 42; }
};
int i = S{};
Run Code Online (Sandbox Code Playgroud)
这完全没问题。如果我们应用C++23来推导它的这个特性,那就是:
struct S {
operator auto(this S) { return 42; }
};
int i = S{};
Run Code Online (Sandbox Code Playgroud)
这也完全没问题。但是,当我替换this S为this auto:
struct S {
operator auto(this auto) { return 42; } …Run Code Online (Sandbox Code Playgroud) c++ language-lawyer type-deduction c++23 explicit-object-parameter
是否可以*this在成员函数内完美转发对象?如果是的话,我们该怎么做呢?如果不是,那么为什么不呢?我们有哪些替代方案可以达到同样的效果。
请参阅下面的代码片段以更好地理解该问题。
class Experiment {
public:
double i, j;
Experiment(double p_i = 0, double p_j = 0) : i(p_i), j(p_j) {}
double sum() { return i + j + someConstant(); }
double someConstant() && { return 10; }
double someConstant() & { return 100; }
};
int main() {
Experiment E(3, 5);
std::cout << std::move(E).sum() << "\n"; // prints: 108
std::cout << E.sum() << "\n"; // prints: 108
}
Run Code Online (Sandbox Code Playgroud)
如果我们认为*this成员函数内的对象double sum()始终是左值或x值(因此是左值),则此输出似乎是预期的。请确认这是否属实。
如何才能完美地将*this对象转发给成员函数 …
在C++23中,推导这一点最终被添加到标准中。
根据我从提案中读到的内容,它开辟了一种创建 mixins 的新方法,并且可以创建递归 lambda。
但是我很困惑,如果这个参数在不使用模板的情况下创建“副本”,因为没有引用,或者显式this参数是否有自己的值类别规则?
自从:
struct hello {
void func() {}
};
Run Code Online (Sandbox Code Playgroud)
可能相当于:
struct hello {
void func(this hello) {}
};
Run Code Online (Sandbox Code Playgroud)
但它们的类型不同,因为对于&hello::func,第一个给出void(hello::*)(),而第二个给出void(*)(hello)
例如,我有这个简单的功能:
struct hello {
int data;
void func(this hello self) {
self.data = 22;
}
};
Run Code Online (Sandbox Code Playgroud)
参数不需要是引用来更改类型this的值吗?hello或者它基本上和以前一样遵循成员函数的 cv-ref 限定符规则?
如何获取具有使用推导此签名的 lambda 的返回类型std::invoke_result_t。
auto lambda = [](this auto& self, int x) -> int {
return x;
};
auto x = std::invoke_result_t<decltype(lambda), int>{}; //won't compile
Run Code Online (Sandbox Code Playgroud)
我是否需要以某种方式指定 self 参数std::invoke_result_t?
我尝试过没有“推导这一点”,并且上面的示例有效。
编辑: 编译器资源管理器链接
struct BananaHolder
{
vector<Banana>& getBananas();
const vector<Banana>& getBananas() const;
};
Run Code Online (Sandbox Code Playgroud)
我的课程充满了这种重复。
有没有更干净、更优雅的替代方案?
c++ getter c++11 function-qualifier explicit-object-parameter
来自提案的 \xc2\xa74.2.7 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#pathological-cases
\n它说:
\n\n\n这些更不可能是真正有用的代码。在此示例中,
\nB既不能转换为A也int,因此这两个函数甚至都不能使用普通成员语法调用。但是,您可以获取指向此类函数的指针并通过该指针调用它们。(&B::bar)(42)有效,如果奇怪,请致电。
但是,它没有指定标准是否不允许将 type-of-self 的显式对象参数隐式转换为特定的另一种类型。
\nstruct A { };\nstruct B {\n void foo(this A&);\n void bar(this int);\n};\nRun Code Online (Sandbox Code Playgroud)\n这是否意味着:
\nstruct A { };\nstruct B {\n operator A() const noexcept;\n void foo(this A);\n};\n\n// ...\n// \'&B::foo\' is of type function pointer not pointer to member function\n// because it uses explicit object parameter.\n(&B::foo)(A{}); \n(&B::foo)(B{});\nB{}.foo(); // will work?\nRun Code Online (Sandbox Code Playgroud)\n将工作?
\n在另一种情况下,这是一个 lambda。由于 lambda 的类型是不可言说的并且始终是相关的。那上面的案例呢?(这个无捕获 lambda …
P0847提出了对成员函数使用显式参数的可能性this。
除了该提案带来的其他好处之外,CRTP 还为没有 C、R 甚至 T 的 CRTP带来了巨大的新可能性。
在 C++ 中实现泛型的常见做法clone是基于 CRTP,例如请参阅此 SO 帖子。
鉴于我们需要clone(virtual或者至少表现为虚拟),允许:
Shape* pCopy = pShape->clone(); // get a copy of the correct runtime type
Run Code Online (Sandbox Code Playgroud)
并且鉴于建议不应声明具有显式 this 参数的成员函数virtual。
是否仍然有办法使用 P0847 来实现具有动态行为且无需 CRTP 的通用克隆?
假设我有以下非常简单的类:
class A
{
public:
static constexpr A make() { return A{}; }
constexpr A() : _v(0) {}
constexpr A& setV(int v) { _v = v; return *this; }
private:
int _v;
};
Run Code Online (Sandbox Code Playgroud)
如果我尝试按如下方式使用它:
int main()
{
volatile A a1;
a1.setV(10);
//OR
//The optimizer will optimize this chain of constexpr calls into a single "store" instruction
a1 = A::make().setV(10); //More chaining here
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该代码将无法编译。
我理解为什么这是真的,基于:定义易失性类对象
我知道解决方案是添加一个额外的方法,如下所示:
class A
{
public:
constexpr A() : _v(0) {}
volatile A& …Run Code Online (Sandbox Code Playgroud) 因此,在我正在处理的项目中尝试对函数指针使用显式对象参数时,我遇到了问题。乍一看,代码在语法上似乎很好,但由于这是一个新功能,我在网上找不到太多信息,所以我不知道为什么会出现随机语法错误。具体来说,错误是“语法错误:')'”
我唯一真正的猜测是,这是某种 MSVC 不完整性/错误,在这种情况下我可能不得不切换到不同的编译器。
///base.h
///...
#include <map>
template <class s>
using FunctionMap = std::map<std::string,void(*)(this s& self)>;
///^ Syntax Error Here
class base{
//...
public:
///Get Map of fPtr
template <class Self>
FunctionMap<Self>* get_scripts(this const Self& self);
}
Run Code Online (Sandbox Code Playgroud)
我预计它可以编译,但它不断出现语法错误。我知道显式对象参数仅在 MSVC 中部分实现。