我们都知道protected
从基类指定的成员只能从派生类自己的实例访问.这是标准的一个特性,这已在Stack Overflow上多次讨论:
但似乎有可能用成员指针来解决这个限制,因为用户chtz 向我展示:
struct Base { protected: int value; };
struct Derived : Base
{
void f(Base const& other)
{
//int n = other.value; // error: 'int Base::value' is protected within this context
int n = other.*(&Derived::value); // ok??? why?
(void) n;
}
};
Run Code Online (Sandbox Code Playgroud)
为什么这可能,它是一个想要的功能或实施中的某个地方或标准的措辞?
从评论中出现了另一个问题:如果Derived::f
用实际调用Base
,是不确定的行为?
c++ protected access-specifier member-pointers language-lawyer
看看这段代码:
template <typename T, void (T::*pfn)()> struct Testee {};
class Tester
{
private:
void foo() {}
public:
using type_t = Testee<Tester, &Tester::foo>;
};
Run Code Online (Sandbox Code Playgroud)
它成功编译g++ -std=c++14 -Wall -Wextra
.
但是,当我改变的顺序foo
和type_t
,发生错误:
$ cat test.cpp
template <typename T, void (T::*pfn)()> struct Testee {};
class Tester
{
public:
using type_t = Testee<Tester, &Tester::foo>;
private:
void foo() {}
};
int main()
{
}
$ g++ -std=c++14 -Wall -Wextra -pedantic test.cpp
test.cpp:6:36: error: incomplete type ‘Tester’ used in nested name specifier …
Run Code Online (Sandbox Code Playgroud) 如果C++ FAQ Lite中的以下内容为真:"函数名称衰减到指向函数的指针"(因为数组名称衰减为指向其第一个元素的指针); 为什么我们必须加入&符号?
typedef int (Fred::*FredMemFn)(char x, float y);
FredMemFn p = &Fred::f;
Run Code Online (Sandbox Code Playgroud)
而不只是:
typedef int (Fred::*FredMemFn)(char x, float y);
FredMemFn p = Fred::f;
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,Fred :: f是一个函数,可以衰减到指向该函数的指针.
我希望这个问题不是那么愚蠢.
昨天,我和我的同事不确定为什么语言禁止这种转换
struct A { int x; };
struct B : virtual A { };
int A::*p = &A::x;
int B::*pb = p;
Run Code Online (Sandbox Code Playgroud)
甚至演员都没有帮助.如果基本成员指针是虚拟基类,为什么标准不支持将基本成员指针转换为派生成员指针?
相关的C++标准参考:
类型"指向
B
cv类型成员的指针"的prvalueT
,其中B
是类类型,可以转换为类型为"指向D
cv类型成员的指针"的prvalueT
,其中D
是派生类(第10条)B
.如果B
不可访问(第11条),模糊(10.2)或虚拟(10.1)基类D
,或虚拟基类的基类D
,则需要进行此转换的程序是不正确的.
函数和数据成员指针都会受到影响.
这可能最好用示例代码显示.以下无法使用g ++编译:
struct Base {
};
struct Derived : public Base {
};
struct Container {
Derived data_;
};
int main(void) {
Base Container::*ptr = &Container::data_;
}
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:invalid conversion from 'Derived Container::*' to Base Container::*'
.语言不允许这样做吗?这是编译器错误吗?我使用了错误的语法吗?
请帮忙!
关于为什么我要这样做的一些背景:我有几个我想主要用作派生类型的成员数据,但我希望能够通过一些常用代码填充它们.数据将以任意顺序出现,并有一个字符串标签,我将用它来选择要填充的相应成员数据.我计划创建一个std::map<std::string, Base Container::*>
通过公共接口为每个成员分配数据.我想避免使用巨型if else
构造来找到正确的成员数据.
我有以下剪切的代码,不编译.
#include <iostream>
struct A {
void foo() {}
};
struct B : public A {
using A::foo;
};
template<typename U, U> struct helper{};
int main() {
helper<void (A::*)(), &A::foo> compiles;
helper<void (B::*)(), &B::foo> does_not_compile;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它自&B::foo
解析后不编译&A::foo
,因此无法与提议的类型匹配void (B::*)()
.由于这是SFINAE模板的一部分,我用它来检查一个非常具体的接口(我强制使用特定的参数类型和输出类型),我希望这可以独立于继承,同时保持检查的可读性.
我尝试的内容包括:
抛出论证的第二部分:
helper<void (B::*)(), (void (B::*)())&B::foo> does_not_compile;
遗憾的是,这并没有帮助,因为第二部分现在不被认为是一个常量表达式,并且失败了.
我已经尝试为变量分配引用,以便检查它.
constexpr void (B::* p)() = &B::foo;
helper<void (B::* const)(), p> half_compiles;
这个代码被clang 3.4接受,但g ++ 4.8.1拒绝它,我不知道谁是对的.
有任何想法吗?
编辑:由于许多评论要求更具体的问题版本,我会在这里写:
我正在寻找的是一种明确检查类是否尊重特定接口的方法.此检查将用于验证模板化函数中的输入参数,以便它们遵守这些函数所需的合约,以便在类和函数不兼容的情况下(即类型特征类型的检查)预先停止编译.
因此,我需要能够验证我请求的每个成员函数的返回类型,参数类型和数量,常量等.最初的问题是我用来验证匹配的更大模板的检查部分.
愚蠢的简化代码示例没有做任何有用的事情,而是对数据成员指针的两个后续分配.第一个分配工作,第二个分配给出编译器错误.大概是因为它是一个嵌套的成员.
问题是:是否真的不可能让成员指针指向嵌套成员,或者我错过了任何花哨的语法?
struct Color {
float Red;
float Green;
float Blue; };
struct Material {
float Brightness;
Color DiffuseColor; };
int main() {
float Material::* ParamToAnimate;
ParamToAnimate = &Material::Brightness; // Ok
ParamToAnimate = &Material::DiffuseColor.Red; // Error! *whimper*
return 0; }
Run Code Online (Sandbox Code Playgroud)
ATM我通过使用字节偏移和大量演员来解决.但这很难看,我最好使用那些成员指针.
是的,我知道之前肯定会出现这个问题(几乎与任何问题一样).是的,我事先搜查过但发现没有令人满意的答案.
谢谢你的时间.
不久前,Borland 在他们的 BCB 环境中引入了 C++ 语言的扩展。这个扩展是一个 __closure 关键字。问题是,是否可以用普通 C++ 或 C++11 实现此类功能?如果您不熟悉 __closure 关键字,下面的代码在注释中提供了解释。
提前致谢!托雷诺
#include <stdio.h>
// __closure keyword is used here !
typedef void (__closure * MemberCallback)(int x, int y, int z);
class A
{
private:
MemberCallback callback;
public:
A() : callback(NULL)
{
}
void setCallback(MemberCallback newCallback)
{
callback = newCallback;
}
void call(int x, int y, int z)
{
if(callback)
callback(x, y, z);
else
printf("NOT SET(%i, %i, %i)\n", x, y, z);
}
};
class B
{
public: …
Run Code Online (Sandbox Code Playgroud) 我想在C++中声明一个成员函数指针,它返回相同的成员函数指针类型
这不起作用:
class MyClass {
public:
typedef FunctionPtr (MyClass::*FunctionPtr)();
}
Run Code Online (Sandbox Code Playgroud)
有人知道解决方案吗?
我正在阅读这个史前元程序示例来检测一个类是否支持成员查找。(或任何其他成员)。
template<typename T>
class DetectFind
{
struct Fallback { int find; };
struct Derived : T, Fallback { };
template<typename U, U> struct Check;
typedef char Yes[1];
typedef char No[2];
template<typename U>
static No& func(Check<int Fallback::*, &U::find>*);
template<typename U>
static Yes& func(...);
public:
typedef DetectFind type;
enum { value = sizeof(func<Derived>(0)) == sizeof(Yes) };
};
int main()
{
std::cout << DetectFind<std::vector<int> >::value << std::endl;
std::cout<< DetectFind<std::set<int> >::value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
直觉上我确实理解这背后的目的,但如果有人让我在 10 天后从头开始写同样的东西,我可能会失败。
原因是我不完全理解这里使用的句法和语言延伸。
有人可以解释以下语法的含义吗?
Check<int Fallback::*, &U::find>*
(我知道它试图在这里从 SFIANE …c++ ×10
member-pointers ×10
c++11 ×2
sfinae ×2
templates ×2
closures ×1
declaration ×1
match ×1
pointers ×1
protected ×1
return-type ×1