如何检测类中是否存在特定的成员变量?

2024-03-29

为了创建算法模板函数,我需要知道作为模板参数的类中的 x 或 X (以及 y 或 Y)。当我将我的函数用于 MFC CPoint 类或 GDI+ PointF 类或其他一些类时,它可能很有用。他们都在其中使用不同的 x 。我的解决方案可以简化为以下代码:


template<int> struct TT {typedef int type;};
template<class P> bool Check_x(P p, typename TT<sizeof(&P;::x)>::type b = 0) { return true; }
template<class P> bool Check_x(P p, typename TT<sizeof(&P;::X)>::type b = 0) { return false; }

struct P1 {int x; };
struct P2 {float X; };
// it also could be struct P3 {unknown_type X; };

int main()
{
    P1 p1 = {1};
    P2 p2 = {1};

    Check_x(p1); // must return true
    Check_x(p2); // must return false

    return 0;
}

但它不能在 Visual Studio 中编译,而在 GNU C++ 中编译。通过 Visual Studio,我可以使用以下模板:


template<class P> bool Check_x(P p, typename TT<&P;::x==&P;::x>::type b = 0) { return true; }
template<class P> bool Check_x(P p, typename TT<&P;::X==&P;::X>::type b = 0) { return false; }

但它不能在 GNU C++ 中编译。有通用的解决方案吗?

UPD:这里的结构P1和P2仅作为示例。可能存在任何具有未知成员的类。

附:请不要在这里发布 C++11 解决方案,因为它们很明显并且与问题无关。


这是一个比以下更简单的解决方案约翰内斯·绍布 (Johannes Schaub) - 英文 https://stackoverflow.com/users/34509/johannes-schaub-litb's one https://stackoverflow.com/a/1007175/1137388。它需要 C++11。

#include <type_traits>

template <typename T, typename = int>
struct HasX : std::false_type { };

template <typename T>
struct HasX <T, decltype((void) T::x, 0)> : std::true_type { };

Update:一个简单的示例以及其工作原理的解释。

对于这些类型:

struct A { int x; };
struct B { int y; };

we have HasX<A>::value == true and HasX<B>::value == false。让我们看看为什么。

首先回想一下std::false_type and std::true_type have a static constexpr bool成员名为value设置为false and true, 分别。因此,这两个模板HasX上面继承了这个成员。 (第一个模板来自std::false_type第二个来自std::true_type.)

让我们从简单的开始,然后逐步进行,直到我们得到上面的代码。

1)起点:

template <typename T, typename U>
struct HasX : std::false_type { };

在这种情况下,也就不足为奇了:HasX源自于std::false_type因此HasX<bool, double>::value == false and HasX<bool, int>::value == false.

2) 违约U:

// Primary template
template <typename T, typename U = int>
struct HasX : std::false_type { };

鉴于U默认为int, Has<bool>实际上意味着HasX<bool, int>因此,HasX<bool>::value == HasX<bool, int>::value == false.

3)增加专业:

// Primary template
template <typename T, typename U = int>
struct HasX : std::false_type { };

// Specialization for U = int
template <typename T>
struct HasX<T, int> : std::true_type { };

一般来说,由于主要模板,HasX<T, U>源自于std::false_type。然而,有一个专门针对U = int其源自std::true_type。所以,HasX<bool, double>::value == false but HasX<bool, int>::value == true.

感谢默认的U, HasX<bool>::value == HasX<bool, int>::value == true.

4) decltype和一种奇特的说法int:

这里有点离题,但是请耐心听我说。

基本上(这并不完全正确),decltype(expression)产生的类型表达。例如,0有类型int thus, decltype(0) means int。类似地,1.2有类型double因此,decltype(1.2) means double.

考虑一个带有此声明的函数:

char func(foo, int);

where foo是某种类类型。如果f是一个类型的对象foo, then decltype(func(f, 0)) means char(返回的类型func(f, 0)).

现在,表达(1.2, 0)使用(内置)逗号运算符按顺序计算两个子表达式(即,首先1.2进而0),丢弃第一个值并产生第二个值。因此,

int x = (1.2, 0);

相当于

int x = 0;

把这个和decltype给出了decltype(1.2, 0) means int。没什么特别的1.2 or double这里。例如,true有类型bool and decltype(true, 0) means int以及。

班级类型怎么样?例如,什么是decltype(f, 0)意思是?很自然地期望这仍然意味着int但情况可能并非如此。事实上,逗号运算符可能存在类似于函数的重载func上面需要一个foo and an int并返回一个char。在这种情况下,decltype(foo, 0) is char.

我们如何避免使用逗号运算符的重载?好吧,没有办法重载 a 的逗号运算符void操作数,我们可以将任何内容转换为void。所以,decltype((void) f, 0) means int。的确,(void) f casts f from foo to void它基本上什么也没做,只是说表达式必须被视为具有类型void。然后使用内置运算符逗号((void) f, 0)结果是0其中有类型int。因此,decltype((void) f, 0) means int.

这个演员阵容真的有必要吗?好吧,如果逗号运算符没有重载foo and int那么这是没有必要的。我们可以随时检查源代码,看看是否有这样的运算符。但是,如果这出现在模板中并且f有类型V这是一个模板参数,那么就不再清楚(甚至不可能知道)逗号运算符的这种重载是否存在。为了通用,我们无论如何都会进行投射。

底线:decltype((void) f, 0)是一种奇特的表达方式int.

5)SFINAE:

这是一门完整的科学;-) 好吧,我有点夸张,但它也不是很简单。所以我会将解释保持在最低限度。

SFINAE 代表替换失败不是错误。这意味着当模板参数被类型替换时,可能会出现非法的 C++ 代码,但是,在某些情况下,而不是中止编译,编译器只是忽略有问题的代码,就好像它不存在一样。让我们看看它如何应用于我们的案例:

// Primary template
template <typename T, typename U = int>
struct HasX : std::false_type { };

// Specialization for U = int
template <typename T>
struct HasX <T, decltype((void) T::x, 0)> : std::true_type { };

又是在这里,decltype((void) T::x, 0)是一种奇特的表达方式int但得益于 SFINAE。

When T替换为类型时,可能会出现无效的构造。例如,bool::x不是有效的 C++,因此替换T with bool in T::x产生无效的构造。根据 SFINAE 原则,编译器不会拒绝代码,它只是忽略(部分)它。更准确地说,正如我们所看到的HasX<bool>实际上意味着HasX<bool, int>。专业化为U = int应该选择,但是在实例化它时,编译器发现bool::x并完全忽略模板专业化,就好像它不存在一样。

此时,代码本质上与上面情况 (2) 中的代码相同,其中仅存在主模板。因此,HasX<bool, int>::value == false.

同样的论点用于bool成立于B since B::x是一个无效的构造(B没有会员x)。然而,A::x没问题,编译器在实例化专门化时没有发现任何问题U = int(或者,更准确地说,对于U = decltype((void) A::x, 0))。因此,HasX<A>::value == true.

6) 取消命名U:

好吧,再次查看(5)中的代码,我们看到名称U除了在其声明中之外没有在任何地方使用(typename U)。然后我们可以取消第二个模板参数的命名,并获得本文顶部显示的代码。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何检测类中是否存在特定的成员变量? 的相关文章

  • 无法使用c#更改视频捕获分辨率

    我正在尝试使用 C 中的 DirectShowNet 更改默认网络摄像头分辨率 据我所知 我需要通过调用 windows win32 api dll 中内置的 VideoInfoHeader 类来更改它以进行 avi 捕获 我有来自 Dir
  • 如何在 ASP.NET MVC 中将 XML 文件发送到客户端

    在 ASP NET MVC 中 我有一个数据库表 我想在某个视图页面上有一个按钮 如果某个用户单击该按钮 我的应用程序将生成包含数据库中所有行的 XML 文件 然后 应将包含 XML 的文件发送到客户端 以便用户看到下载弹出窗口 同样 我希
  • 采用 std::vector 或 std::array 的模板函数

    我有一个函数 当前接受 2 个向量 其中可以包含任何普通的旧数据 template
  • 如何使用 Entity Framework 和 Identity 解决对象处置异常 ASP.NET Core

    我正在尝试编写一个控制器 该控制器接收来自 AJAX 调用的请求并通过 DBContext 对数据库执行一些调用 但是 当我发出命令时var user await GetCurrentUserAsynch 在对 DBContext 的任何调
  • getline 之后返回到文件开头

    所以我已经从文件中读取了所有行 while getline ifile line logic 其中 ifile 是 ifstream line 是字符串 我的问题是我现在想再次使用 getline 并且似乎无法返回到文件的开头 因为运行 c
  • 信号与信号2

    我的应用程序可能会受益于使用 boost 的信号库之一而不是本土解决方案 该应用程序是多线程的 但执行信号处理的部分是单线程的 如果多线程不是问题 是否有任何理由更喜欢 Boost Signals2 而不是 Boost Signal Boo
  • 对 ExecuteNonQuery() 的单次调用是原子的

    对 ExecuteNonQuery 的单次调用是否是原子的 或者如果单个 DbCommand 中有多个 sql 语句 那么使用事务是否有意义 请参阅我的示例以进行说明 using var ts new TransactionScope us
  • C# 中 PKCS11Interop 库的线程安全使用 [已关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在使用 PKCS11Interop 在 HSM 内执行密钥管理操作 我使用的 HSM 是 Thales PCI Express 下面是
  • 从内存流播放视频文件

    只是好奇看看这是否可能 我有一个 Windows 应用程序 它从我的电脑上的 avi 文件读取所有字节 然后将其存储在 byte 中 现在我的内存中有 avi 文件 我想直接从内存将其加载到某种视频播放器控件中 我尝试过使用 wmplaye
  • 为什么像 BindingList 或 ObservableCollection 这样的类不是线程安全的?

    我一次又一次发现自己必须编写 BindingList 和 ObservableCollection 的线程安全版本 因为当绑定到 UI 时 这些控件无法从多个线程更改 我想理解的是why情况就是这样 这是设计错误还是故意的 问题是设计一个线
  • C# 中的抽象类和接口类有什么不同?

    C 中的抽象类和接口类有什么不同 An 接口不是类 它只是一个contract定义了public一个类的成员must实施 抽象类只是一个类 您从中可以cannot创建一个实例 通常您会使用它来定义一个基类 该基类定义了一些virtual方法
  • 如何调试.NET Windows Service OnStart方法?

    我用 NET 编写的代码仅在作为 Windows 服务安装时才会失败 该故障甚至不允许服务启动 我不知道如何进入 OnStart 方法 如何 调试 Windows 服务应用程序 http msdn microsoft com en us l
  • 检测反射 DLL 注入

    在过去的几年中 恶意软件 以及一些渗透测试工具 如 Metasploit 的 meterpreter 负载 已经开始使用反射 DLL 注入 PDF http www harmonysecurity com files HS P005 Ref
  • ASP.NET MVC 动作过滤器

    有谁知道即使在 CATCH 块中 ActionFilterAttribute 类的 OnResultExecuted 方法是否也会执行 ie CookiesActions public ActionResult Login Usuarios
  • 本地时间的内存需要释放吗?

    void log time t current time 0 tm ptm localtime current stuf 只是想确定 我是否需要在方法结束时释放 tm 指针分配的内存 不 你不应该释放它 该结构是静态分配的 检查文档 htt
  • 使用 dateTimePicker 在 DataGridView 中编辑日期

    我有一个DateTime我的 WinForms 中的专栏DataGridView 目前只能通过手动输入日期来编辑该字段 例如 2010 09 02 需要什么才能拥有一个DateTimePicker 或同等 用作编辑器 DataGridVie
  • 在 C# .NET 中对非 ASCII 字符进行编码

    我想向我的应用程序发送的电子邮件添加自定义标头 标头名称只能包含 ASCII 字符 但对于值和用户可能会输入 UTF 8 字符 我必须对它们进行 Base64 编码 此外 我还必须将它们解码回 UTF 8 以便在 UI 中向用户显示它们 最
  • 使用 cmake 将两种解决方案合二为一

    我有两个单独的 Visual Studio 2013 解决方案 我想将它们迁移到一个解决方案中 因为第一个解决方案 使用 Qt 充当第二个解决方案的 GUI 最后 我希望有一个结构如下的单一解决方案 Solution All Build P
  • 实体框架读取列但阻止其更新

    给定一个数据库表 其中有一列包含历史数据但不再填充 实体框架中是否有一种方法可以读取该列 但在使用相同的模型对象时防止它被更新 例如我有一个对象 public class MyObject public string CurrentData
  • 使用任务的经典永无止境的线程循环?

    给出了一个非常常见的线程场景 宣言 private Thread thread private bool isRunning false Start thread new Thread gt NeverEndingProc thread S

随机推荐