如果我foo()首先在基类中定义了虚函数B,然后在派生类中重写D,那么如何B::foo以指向成员函数的方式存储地址,以便在调用它时,调用将表现为一个有资格的id(如pd->B::foo())?
例:
struct B {
virtual int foo() { return 1; }
};
struct D: public B {
virtual int foo() { return 2; }
};
int main(int argc, char * argv[]) {
D* pd = new D();
int (B::*pf)() = &B::foo;
int r = (pd->*pf)();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这会打电话D::foo().我可以初始化pf,即使动态类型是一个覆盖的类,它(pd->*pf)()也会调用吗?B::foo()pdfoo()
(在任何人问之前,我真的不想这样做,我只是好奇,如果可能的话.)
最近我发现shared_ptr没有指向成员运算符的指针->*.我创建了简单的例子:
template <typename Pointer, typename Function, typename... Args>
auto invoke1(Pointer p, Function f, Args... args) -> decltype((p->*f)(args...))
{
return (p->*f)(args...);
}
struct A {
void g() { std::cout << "A::g()\n"; }
};
int main() {
A a;
invoke1(&a, &A::g); // works!!
std::shared_ptr<A> sa = std::make_shared<A>();
invoke1(sa, &A::g); // compile error!!
}
Run Code Online (Sandbox Code Playgroud)
Q1:为什么会这样?为什么shared_ptr没有这个运算符?
我添加了这样的运算符,shared_ptr示例开始工作:
template <typename T, typename Result>
auto operator ->* (std::shared_ptr<T> pointer, Result (T::*function)()) ->decltype(std::bind(function, pointer))
{
return std::bind(function, pointer);
}
template <typename …Run Code Online (Sandbox Code Playgroud) c++ operator-overloading boost-bind shared-ptr pointer-to-member
我不明白为什么为类添加前向声明会将其指针的大小更改为成员类型
#include <iostream>
using namespace std;
int main()
{
//struct CL;
//cout<<sizeof(int (CL::*)())<<endl;
struct CL{};
cout<<sizeof(int (CL::*)())<<endl;
}
Run Code Online (Sandbox Code Playgroud)
输出VS2013:
4
但是如果我取消注释main()中的前两行,那么输出是不同的:
16
16
因此,在struct CL的定义之前只添加一个前向声明只会增加指向CL成员的指针的大小.为什么?我知道成员函数指针的大小取决于类型的结构(例如,虚函数和基类可能会增加它),但为什么sizeof运算符可以应用于指向不完整类型成员的指针?还是不行?我没有在标准中找到它
想象一下我写这个奇怪的原因:
int main()
{
struct S
{
int i;
} var;
int decltype(var)::* pint = &decltype(var)::i;
}
Run Code Online (Sandbox Code Playgroud)
GCC似乎编译得很好,尽管Clang失败了一些不确定的语法相关错误消息.
那么神圣的ISO论文对此有何评论 - 这是否有效?
我最近发现C++中存在.*运算符(以及密切相关的->*运算符).(见这个问题.)
起初看起来很整洁,但为什么我会需要这样的东西呢?链接问题中的两个答案提供了可以从直接函数调用中受益的人为例子.
在直接函数调用不方便的情况下,可以使用函数对象,就像可以使用的lambda函数一样std::sort.这消除了间接级别,因此比使用更高效.*.
链接的问题还提到了此示例的简化版本:
struct A {
int a;
int b;
};
void set_member(A& obj, int A::* ptr, int val){
obj.*ptr = val;
}
int main()
{
A obj;
set_member(obj, &A::b, 5);
set_member(obj, &A::a, 7);
// Both members of obj are now assigned
}
Run Code Online (Sandbox Code Playgroud)
但这样做是非常微不足道的(可能更好的做法,因为它更清洁,并且不会对成员造成不必要的限制A):
struct A {
int a;
int b;
};
void set_me(int& out, int val){
out = val;
}
int main()
{
A obj;
set_me(obj.b, …Run Code Online (Sandbox Code Playgroud) 谁能告诉我为什么对于 MSVC、clang 和 g++,nullptr分配给类型数据成员指针的内部表示是 -1?Class::*对于 64 位系统来说(size_t)1 << 63是最好的,因为如果您nullptr以这种方式使用成员指针,您肯定会接触内核内存并发生崩溃,因此这将是一个很好的调试辅助工具。
-1背后有更深层次的原因吗?
样本:
struct X
{
int x, y;
};
using member_ptr = int X::*;
member_ptr f()
{
return nullptr;
}
Run Code Online (Sandbox Code Playgroud)
...使用 g++ 生成以下二进制文件:
movq $-1, %rax
ret
Run Code Online (Sandbox Code Playgroud) 给出一个示例类:
class Fred
{
public:
Fred()
{
func = &Fred::fa;
}
void run()
{
int foo, bar;
*func(foo,bar);
}
double fa(int x, int y);
double fb(int x, int y);
private:
double (Fred::*func)(int x, int y);
};
Run Code Online (Sandbox Code Playgroud)
我在通过指针"*func(foo,bar)"调用成员函数的行中遇到编译器错误,说:"术语不会计算为带有2个参数的函数".我究竟做错了什么?
标准库中的许多算法接受带有签名的一元谓词,bool (Type & item)因此直接提供指向非静态成员函数的指针不起作用.考虑到通过调用替换operator ()对谓词的直接调用似乎可以解除这种限制,这似乎是相当严格的std::invoke.也许提出的方法有一些我忽略的缺点?
注意:此问题中引用的非静态成员函数应该与常规函数谓词不同,只是因为项引用作为隐式参数而不是显式参数传递.
示例代码(在线编译器):
#include <array>
#include <algorithm>
#include <iostream>
#include <functional>
#include <cassert>
template<typename TForwardIterator, typename TPredicate> TForwardIterator
vtt_find_if
(
const TForwardIterator p_items_begin
, const TForwardIterator p_items_end
, TPredicate && predicate
)
{
TForwardIterator p_item(p_items_begin);
// while((p_items_end != p_item) && (!predicate(*p_item)))
while((p_items_end != p_item) && (!::std::invoke(predicate, *p_item)))
{
++p_item;
}
return(p_item);
}
class t_Ticket
{
private: int m_number;
public:
t_Ticket(const int number): m_number(number) {}
public: bool
Is_Lucky(void) const …Run Code Online (Sandbox Code Playgroud) 演示:
#include<iostream>
struct A { int i = 10; };
struct B : A { };
int main(){
std::cout << "decltype(&B::i) == int A::* ? " << std::boolalpha
<< std::is_same<decltype(&B::i), int A::*>::value << '\n'; //#1
A a;
std::cout << a.*(&A::i) << '\n';
std::cout << "decltype(&B::i) == int B::* ? "
<< std::is_same<decltype(&B::i), int B::*>::value << '\n'; //#2
B b;
std::cout << b.*(&B::i) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
代码打印
decltype(&B::i) == int A::* ? true
10
decltype(&B::i) == int B::* ? false …Run Code Online (Sandbox Code Playgroud)