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

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(使用前将#替换为@)

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

  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • C# 中通过 Process.Kill() 终止的进程的退出代码

    如果在我的 C 应用程序中 我正在创建一个可以正常终止或开始行为异常的子进程 在这种情况下 我通过调用 Process Kill 来终止它 但是 我想知道该进程是否已退出通常情况下 我知道我可以获得终止进程的错误代码 但是正常的退出代码是什
  • 使用 WebClient 时出现 System.Net.WebException:无法创建 SSL/TLS 安全通道

    当我执行以下代码时 System Net ServicePointManager ServerCertificateValidationCallback sender certificate chain errors gt return t
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • Visual Studio 2010 中的数据库设计器

    我需要创建一个全新的 Sql Server 2008 数据库 并希望使用 Visual Studio 2010 Ultimate 中的数据库项目 我已经创建了该项目并在下面添加了一个表格dbo架构 桌子 sql仅以纯文本形式显示 但带有颜色
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • 如何在文本框中插入图像

    有没有办法在文本框中插入图像 我正在开发一个聊天应用程序 我想用图标图像更改值 等 但我找不到如何在文本框中插入图像 Thanks 如果您使用 RichTextBox 进行聊天 请查看Paste http msdn microsoft co

随机推荐