标准库中聚合可初始化性的类型特征?

2024-04-18

C++标准库有std::is_constructible<Class, T...> http://en.cppreference.com/w/cpp/types/is_constructible检查是否可以从给定类型作为参数构造一个类。

例如,如果我有一堂课MyClass它有一个构造函数MyClass(int, char), then std::is_constructible<MyClass, int, char>::valuetrue.

是否有类似的标准库类型特征可以检查聚合初始化是否有效,即MyClass{int, char}格式良好并返回MyClass?

我的用例:

我想编写一个函数模板来转换std::tuple使用聚合初始化的(通常是 POD)类,具有以下签名:

template <typename Class, typename... T>
inline Class to_struct(std::tuple<T...>&& tp);

为了防止用户以无效的方式使用该功能Class,我可以写一个static_assert在此函数内检查是否给定tp参数具有可转换为成员的类型Class。这似乎是一种类型特征is_aggregate_initializable<Class, T...>会派上用场的。

我可以推出自己的此特征的实现,但仅供参考,标准库中是否存在我忽略的这样的特征,或者即将成为标准库的一部分的特征?


从评论中的讨论和浏览 C++ 参考来看,似乎没有聚合可初始化性和列表可初始化性的标准库类型特征,至少达到 C++17。

评论中强调,两者之间存在区别列表可初始化性 http://en.cppreference.com/w/cpp/language/list_initialization一般来说 (Class{arg1, arg2, ...}) and 聚合可初始化性 http://en.cppreference.com/w/cpp/language/aggregate_initialization.

列表可初始化性(具体来说direct列表可初始化性)更容易为其编写类型特征,因为该特征仅依赖于某种语法的有效性。对于我测试是否可以从元组的元素构造结构的用例,直接列表可初始化性似乎更合适。

实现此特征的可能方法(使用适当的 SFINAE)如下:

namespace detail {
    template <typename Struct, typename = void, typename... T>
    struct is_direct_list_initializable_impl : std::false_type {};

    template <typename Struct, typename... T>
    struct is_direct_list_initializable_impl<Struct, std::void_t<decltype(Struct{ std::declval<T>()... })>, T...> : std::true_type {};
}

template <typename Struct, typename... T>
using is_direct_list_initializable = detail::is_direct_list_initializable_impl<Struct, void, T...>;

template<typename Struct, typename... T>
constexpr bool is_direct_list_initializable_v = is_direct_list_initializable<Struct, T...>::value;

然后我们可以通过执行以下操作来测试直接列表的可初始化性is_direct_list_initializable_v<Class, T...>.

这也适用于移动语义和完美转发,因为std::declval遵守完善的转发规则。

聚合可初始化性不太简单,但有一个解决方案可以涵盖大多数情况。聚合初始化要求被初始化的类型是聚合(请参阅关于有关聚合初始化的 C++ 参考 http://en.cppreference.com/w/cpp/language/aggregate_initialization),我们有一个 C++17 特征std::is_aggregate http://en.cppreference.com/w/cpp/types/is_aggregate检查类型是否是聚合。

但是,这并不意味着仅仅因为类型是聚合,通常的直接列表初始化就会无效。仍然允许与构造函数匹配的正常列表初始化。例如,以下编译:

struct point {
    int x,y;
};

int main() {
    point e1{8}; // aggregate initialization :)
    point e2{e1}; // this is not aggregate initialization!
}

为了禁止这种列表初始化,我们可以利用聚合不能具有自定义(即用户提供的)构造函数这一事实,因此非聚合初始化必须只有一个参数,并且Class{arg}会满足std::is_same_v<Class, std::decay_t<decltype(arg)>>.

幸运的是,我们不能拥有与其封闭类相同类型的成员变量 https://stackoverflow.com/questions/4941629/why-cant-we-declare-object-of-a-class-inside-the-same-class,因此以下内容无效:

struct point {
    point x;
};

对此有一个警告:允许对同一对象的引用类型,因为成员引用可以是不完整的类型(GCC、Clang 和 MSVC 都接受这一点,没有任何警告):

struct point {
    point& x;
};

虽然不寻常,该代码根据标准有效 https://stackoverflow.com/questions/22098834/class-that-holds-a-reference-to-itself。我没有解决方案来检测这种情况并确定point可以使用类型的对象进行聚合初始化point&.

忽略上面的警告(很少需要使用这种类型),我们可以设计一个可行的解决方案:

template <typename Struct, typename... T>
using is_aggregate_initializable = std::conjunction<std::is_aggregate<Struct>, is_direct_list_initializable<Struct, T...>, std::negation<std::conjunction<std::bool_constant<sizeof...(T) == 1>, std::is_same<std::decay_t<std::tuple_element_t<0, std::tuple<T...>>>, Struct>>>>;

template<typename Struct, typename... T>
constexpr bool is_aggregate_initializable_v = is_aggregate_initializable<Struct, T...>::value;

它看起来不太好,但功能符合预期。

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

标准库中聚合可初始化性的类型特征? 的相关文章

  • ASP.NET Core Serilog 未将属性推送到其自定义列

    我有这个设置appsettings json对于我的 Serilog 安装 Serilog MinimumLevel Information Enrich LogUserName Override Microsoft Critical Wr
  • 当我使用“control-c”关闭发送对等方的套接字时,为什么接收对等方的套接字不断接收“”

    我是套接字编程的新手 我知道使用 control c 关闭套接字是一个坏习惯 但是为什么在我使用 control c 关闭发送进程后 接收方上的套接字不断接收 在 control c 退出进程后 发送方的套接字不应该关闭吗 谢谢 我知道使用
  • UML类图:抽象方法和属性是这样写的吗?

    当我第一次为一个小型 C 项目创建 uml 类图时 我在属性方面遇到了一些麻烦 最后我只是将属性添加为变量 lt
  • 从父类调用子类方法

    a doStuff 方法是否可以在不编辑 A 类的情况下打印 B did stuff 如果是这样 我该怎么做 class Program static void Main string args A a new A B b new B a
  • 将布尔参数传递给 SQL Server 存储过程

    我早些时候问过这个问题 我以为我找到了问题所在 但我没有 我在将布尔参数传递给存储过程时遇到问题 这是我的 C 代码 public bool upload false protected void showDate object sende
  • 在 Visual Studio 2008 上设置预调试事件

    我想在 Visual Studio 中开始调试程序之前运行一个任务 我每次调试程序时都需要运行此任务 因此构建后事件还不够好 我查看了设置的 调试 选项卡 但没有这样的选项 有什么办法可以做到这一点吗 你唯一可以尝试的 IMO 就是尝试Co
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • Qt moc 在头文件中实现?

    是否可以告诉 Qt MOC 我想声明该类并在单个文件中实现它 而不是将它们拆分为 h 和 cpp 文件 如果要在 cpp 文件中声明并实现 QObject 子类 则必须手动包含 moc 文件 例如 文件main cpp struct Sub
  • Web API - 访问 DbContext 类中的 HttpContext

    在我的 C Web API 应用程序中 我添加了CreatedDate and CreatedBy所有表中的列 现在 每当在任何表中添加新记录时 我想填充这些列 为此目的我已经覆盖SaveChanges and SaveChangesAsy
  • 从路径中获取文件夹名称

    我有一些路c server folderName1 another name something another folder 我如何从那里提取最后一个文件夹名称 我尝试了几件事 但没有成功 我只是不想寻找最后的 然后就去休息了 Thank
  • Github Action 在运行可执行文件时卡住

    我正在尝试设置运行google tests on a C repository using Github Actions正在运行的Windows Latest 构建过程完成 但是当运行测试时 它被卡住并且不执行从生成的可执行文件Visual
  • 如何将单个 char 转换为 int [重复]

    这个问题在这里已经有答案了 我有一串数字 例如 123456789 我需要提取它们中的每一个以在计算中使用它们 我当然可以通过索引访问每个字符 但是如何将其转换为 int 我研究过 atoi 但它需要一个字符串作为参数 因此 我必须将每个字
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 如何使我的表单标题栏遵循 Windows 深色主题?

    我已经下载了Windows 10更新包括黑暗主题 文件资源管理器等都是深色主题 但是当我创建自己的 C 表单应用程序时 标题栏是亮白色的 如何使我自己的桌面应用程序遵循我在 Windows 中设置的深色主题 你需要调用DwmSetWindo
  • 需要哪个版本的 Visual C++ 运行时库?

    microsoft 的最新 vcredist 2010 版 是否包含以前的版本 2008 SP1 和 2005 SP1 还是我需要安装全部 3 个版本 谢谢 你需要所有这些
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce
  • C 中的异或运算符

    在进行按位操作时 我在确定何时使用 XOR 运算符时遇到一些困难 按位与和或非常简单 当您想要屏蔽位时 请使用按位 AND 常见用例是 IP 寻址和子网掩码 当您想要打开位时 请使用包含或 然而 XOR 总是让我明白 我觉得如果在面试中被问
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框
  • 防止索引超出范围错误

    我想编写对某些条件的检查 而不必使用 try catch 并且我想避免出现 Index Out of Range 错误的可能性 if array Element 0 Object Length gt 0 array Element 1 Ob

随机推荐