template-meta-programming 相关问题

模板元编程是一种元编程技术,其中编译器使用模板生成临时源代码,该代码由编译器与其余源代码合并然后编译。

一种编译时方法来测试模板参数 T 是否定义了自己的(静态)方法,而不考虑 T 的基类定义的方法

我在代码中使用静态类版本 CRTP(奇怪的重复模板模式)。那是: // 使用 CRTP 的基类模板 模板 基类{ 民众: // 静态

回答 1 投票 0

由enable_if控制的模板函数专门化

假设我有一个模板 is_my_tag ,它解析为 true_type 或 false_type,具体取决于 T。 结构体my_tag; template struct is_my_tag : std::false_type {}; 模板<...

回答 1 投票 0

推导出模板参数数量减少的模板类

我有一个包装类,它采用 template 类作为参数。但是,我有一个带有额外参数的类,例如 template Special,我会...

回答 1 投票 0

将运行时变量简洁地映射到模板参数,用于_many_函数

问题 我有一个模板化函数 模板 无效 myfunc(int a) { // 使用 N 进行编译时优化的内容 } 我在编译时实例化它来为

回答 1 投票 0

使用反射(编译时)将结构的元素映射到不同的向量元素

我最近碰壁了,似乎找不到一个优雅的解决方案来解决我的问题: 我有不同数量元素的不同数据结构,所有这些都与指针大小对齐并且......

回答 1 投票 0

如何替换给定类型中的模板参数?

假设名为 B 的模板参数的类型为 C(在实例化时),我如何从 B 构造 C? 这是我的代码的最小化摘录: 模板 CL...

回答 2 投票 0

如何提取没有模板参数的对象的类模板?

如何提取对象的模板来声明具有不同模板参数的新对象? 如果可能的话,我正在寻找具有以下用法的东西: #包括 如何提取对象的模板来声明具有不同模板参数的新对象? 如果可能的话,我正在寻找具有以下用法的东西: #include <vector> int main() { std::vector<float> a; std::array<int, 7> b; get_template<decltype(a), unsigned> new_a; // std::vector<unsigned> get_template<decltype(b), float, 85> new_b; // std::array<float, 85> return 0; } 如何提取对象的模板来声明具有不同模板参数的新对象? 如果可能的话[...] 是的,您可以执行以下操作: // Primary template template<typename T> struct get_template; // Specialization for std::vector template<typename T, typename Allocator> struct get_template<std::vector<T, Allocator>> { template<typename U, typename UAllocator = std::allocator<U>> using type = std::vector<U, UAllocator>; }; // Specialization for std::array template<typename T, std::size_t N> struct get_template<std::array<T, N>> { template<typename U, std::size_t UN = N> using type = std::array<U, UN>; }; // ... so on for other containers! // Helper alias for both specializations template<typename Container, typename U, auto... Ts> using get_template_t = typename get_template<Container>::template type<U, Ts...>; 你会这样使用它: std::vector<float> a; std::array<int, 7> b; get_template_t<decltype(a), unsigned> new_a; // std::vector<unsigned> get_template_t<decltype(b), float, 85> new_b; // std::array<float, 85> 观看现场演示 您可以专门针对类型和非类型参数的特定组合,但您无法拥有完全通用的解决方案。 // Primary template template<typename T> struct get_template; // Specialization for types with no non-type parameters template<template<typename...> typename Container, typename... Ts> struct get_template<Container<Ts...>> { template<typename... Us> using type = Container<Us...>; }; // Specialization for types with a type parameter followed by non-type parameters template<template<typename, auto...> typename Container, typename T, auto... Ns> struct get_template<Container<T, Ns...>> { template<typename U, auto... UNs> using type = Container<U, UNs...>; }; template<typename Container, typename... Us> using get_template_t = typename get_template<Container>::template type<Us...>; template<typename Container, typename T, auto... Us> using get_template_value_t = typename get_template<Container>::template type<T, Us...>; std::vector<float> a; std::array<int, 7> b; static_assert(std::same_as<get_template_t<decltype(a), unsigned>, std::vector<unsigned>>); static_assert(std::same_as<get_template_value_t<decltype(b), float, 85>, std::array<float, 85>>);

回答 2 投票 0

std::void_t 与 SFINAE 用法中的自定义函数

#包括 模板 结构体CheckX { 使用 TypeOfX = decltype(T::x); 使用值=无效; }; 结构A { }; 结构B { 整数x; }; 模板 #include <iostream> template <typename T> struct CheckX { using TypeOfX = decltype(T::x); using Value = void; }; struct A { }; struct B { int x; }; template <typename T , typename = void> struct Res { static constexpr bool value = false; }; // template <typename T> // struct Res<T , std::void_t<decltype(T::x)>> // { // static constexpr bool value = true; // }; template <typename T> struct Res<T , typename CheckX<T>::Value> { static constexpr bool value = true; }; int main() { std::cout << Res<B>::value << '\n'; std::cout << Res<A>::value << '\n'; } 这些是我想要实现一个检查器的代码,该检查器检查结构中是否存在成员x。我注意到使用自定义 CheckX 会导致编译失败,而 std 库 std::void_t 会完成这项工作。我在这里缺少什么? 第一个版本(带有 void_t)完全按照您的预期工作: 对于类 A,当考虑此 std::void_t<decltype(T::x)> 时,A::x 会导致替换失败(由于缺少 Res)。 这是经典的 SFINAE。 因此,这个版本的 Res 被丢弃,留下默认的 Res 和 value = false。 第二个版本(带有CheckX<T>)甚至没有进入SFINAE阶段Res: 为了检查 CheckX<T>::Value,首先将 CheckX<T> 实例化。作为其中的一部分,using TypeOfX = decltype(T::x)被解析,并且由于A不包含x,decltype(T::x)会触发错误。 解析 using 的这个 A 声明不是 Res 的 SFINAE 的一部分(它是在初步阶段完成的)。 注意,这种场景正是std::void_t的确切目的: 将任何类型的序列映射到该类型的实用程序元函数 空白。 此元函数是利用 SFINAE 先验的便捷方法 C++20 的概念,特别是有条件删除 根据表达式是否为候选集的函数 在未评估的上下文中有效(例如 decltype 的操作数 表达式),允许存在单独的函数重载或 基于支持的操作的专业化。 (重点是我的) 另请参阅 cppreference.com 页面中的 struct has_type_member 示例。

回答 1 投票 0

在 C++ 中使用自定义随机引擎包装器时出现 std::variant 编译错误

我正在开发一个 C++ 项目,在该项目中我实现了 RandomEngineWrapper 类,以使用 std::variant 封装各种随机数引擎。但是,我在尝试时遇到编译错误...

回答 1 投票 0

类型选择器特征

我需要一个 type_chooser 特征,看起来像 使用 selected_type = type_chooser; 并且会像 if (bool1) 返回 T1; 否则如果(布尔2)

回答 1 投票 0

如何在编译时对类型进行排序?

考虑以下程序: #包括 #包括 #包括 #包括 模板 结构有序{}; 模板 考虑以下程序: #include <tuple> #include <vector> #include <iostream> #include <type_traits> template <class T> struct ordered {}; template <class... T> struct ordered<std::tuple<T...>> { using type = /* a reordered tuple */; }; template <class T> using ordered_t = typename ordered<T>::type; int main(int argc, char* argv[]) { using type1 = std::tuple<char, std::vector<int>, double>; using type2 = std::tuple<std::vector<int>, double, char>; std::cout << std::is_same_v<type1, type2> << "\n"; // 0 std::cout << std::is_same_v<ordered_t<type1>, ordered_t<type2>> << "\n"; // 1 return 0; } ordered 帮助器必须重新排序元组中的类型,这样两个具有相同类型但顺序不同的元组会产生相同的元组类型:可以是第一个、第二个,甚至另一个:它只需具有相同的大小和相同的元素,但顺序不同(无论这个顺序如何)。 是否可以使用模板元编程技术在编译时执行此操作? 困难的部分是想出一种订购类型的方法。按谓词对类型列表进行排序是一件苦差事,但也是可行的。我在这里只关注比较谓词。 一种方法是创建一个类模板,为每种类型定义唯一的 id。这很有效,并且可以轻松编写比较器: template <typename T, typename U> constexpr bool cmp() { return unique_id_v<T> < unique_id_v<U>; } 但是提出这些唯一的 ID 是一个不一定可行的障碍。您是否将它们全部注册在一个文件中?这并不能很好地扩展。 如果我们能够...获取所有类型的 names 作为编译时字符串,那就太好了。反思会给我们这个,然后这个问题就变得微不足道了。在那之前,我们可以做一些更肮脏的事情:使用__PRETTY_FUNCTION__。 gcc 和 clang 都可以在 constexpr 上下文中使用该宏,尽管它们对此字符串具有不同的格式。如果我们有这样的签名: template <typename T, typename U> constexpr bool cmp(); 然后 gcc 将 cmp<char, int> 报告为 "constexpr bool cmp() [with T = char; U = int]",而 clang 将其报告为 "bool cmp() [T = char, U = int]"。它是不同的......但足够接近,我们可以使用相同的算法。基本上是:找出 T 和 U 在那里,然后进行正常的字符串字典比较: constexpr size_t cstrlen(const char* p) { size_t len = 0; while (*p) { ++len; ++p; } return len; } template <typename T, typename U> constexpr bool cmp() { const char* pf = __PRETTY_FUNCTION__; const char* a = pf + #ifdef __clang__ cstrlen("bool cmp() [T = ") #else cstrlen("constexpr bool cmp() [with T = ") #endif ; const char* b = a + 1; #ifdef __clang__ while (*b != ',') ++b; #else while (*b != ';') ++b; #endif size_t a_len = b - a; b += cstrlen("; U = "); const char* end = b + 1; while (*end != ']') ++end; size_t b_len = end - b; for (size_t i = 0; i < std::min(a_len, b_len); ++i) { if (a[i] != b[i]) return a[i] < b[i]; } return a_len < b_len; } 一些测试: static_assert(cmp<char, int>()); static_assert(!cmp<int, char>()); static_assert(!cmp<int, int>()); static_assert(!cmp<char, char>()); static_assert(cmp<int, std::vector<int>>()); 这不是最漂亮的实现,我不确定它是否受到标准的有意义认可,但它可以让您编写排序,而无需手动且仔细地注册所有类型。它在 clang 和 gcc 上编译。所以也许这已经足够好了。 这是对 Barry 提出的方法的轻微修改,该方法适用于 Visual Studio。而不是创建存储函数名称的编译时字符串: template <typename T, typename U> constexpr bool cmp() 此方法直接比较 type_name< T>::name() 返回的两个类型的名称。当宏 __PRETTY_FUNCTION__ 返回的类型 T 和 U 的名称用逗号分隔时,Barry 的方法不起作用,因为当 T 或 U 是类或函数模板时,逗号也可以分隔模板参数。 // length of null-terminated string constexpr size_t cstrlen(const char* p) { size_t len = 0; while (*p) { ++len; ++p; } return len; } // constexpr string representing type name template<class T> struct type_name { static constexpr const char* name() { #if defined (_MSC_VER) return __FUNCSIG__; #else return __PRETTY_FUNCTION__; #endif }; }; // comparison of types based on type names template<class T1, class T2> constexpr bool less() { const char* A = type_name<T1>::name(); const char* B = type_name<T2>::name(); size_t a_len = cstrlen(A); size_t b_len = cstrlen(B); size_t ab_len = (a_len < b_len) ? a_len : b_len; for (size_t i = 0; i < ab_len; ++i) { if (A[i] != B[i]) return A[i] < B[i]; } return a_len < b_len; } // simple checks template<class ... Type> struct list; static_assert(less<list<int, void, list<void, int>>, list<int, void, list<void, void>>>()); static_assert(less<list<int, void, list<void, int>>, list<int, void, list<void, int>, int>>()); 此方法适用于VS。我不确定它是否适用于 Clang 或 GCC。 tl;dr:在编译时获取类型名称,并按该名称排序。 在我看来,之前的答案有点特殊——至少在实施方面是这样。 此时,我们有一个非常好的、支持多编译器的函数,用于获取类型名称作为编译时字符串和字符串视图。我在这里只引用它的签名: template <typename T> constexpr std::string_view type_name(); 这构成了从类型到编译时可比较值的单射映射。鉴于这些,您可以轻松实现类似“选择排序”的过程来获取每种类型的相对顺序。最后,您使用这些顺序组装一个新的元组。

回答 3 投票 0

无法实例化从约束分派的专用模板类

作为上一个问题的后续:给定一个任意容器,推导出相关类型的容器类型,其中@marek-r建议创建模板专业化,例如: 模板 作为上一个问题的后续:给出任意容器,推导相关类型的容器类型,其中@marek-r建议创建模板专业化,例如: template<template<typename> typename Wrapper, typename Container> struct repack; template<template<typename> typename Wrapper, typename ValueT, std::size_t N> struct repack<Wrapper, std::array<ValueT, N>> { using type = std::array<Wrapper<ValueT>, N>; }; template<template<typename> typename Wrapper, typename ValueT> struct repack<Wrapper, std::vector<ValueT>> { using type = std::vector<Wrapper<ValueT>>; }; template<template<typename> typename Wrapper, typename Key, typename Value> struct repack<Wrapper, std::map<Key, Value>> { using type = std::map<Wrapper<Key>, Wrapper<Value>>; }; 或链接:https://godbolt.org/z/naz9v48vb 通过尝试使其更通用,我用模板化模板参数交换了 vector 和 map,并通过检查 value_type 是否与 pair<const key_type, mapped_type> 相同: 使用 c++20 约束分派每个解决方案 template<template<typename> typename Wrapper, template<typename, typename> typename Mapped_Container, typename Key, typename Value> requires std::is_same_v< typename Mapped_Container<Key, Value>::value_type, std::pair<const typename Mapped_Container<Key, Value>::key_type, typename Mapped_Container<Key, Value>::mapped_type>> struct repack<Wrapper, Mapped_Container<Key, Value>> { using type = Mapped_Container<Wrapper<Key>, Wrapper<Value>>; }; template<template<typename> typename Wrapper, template<typename> typename Unmapped_Container, typename Value> struct repack<Wrapper, Unmapped_Container<Value>> { using type = Unmapped_Container<Wrapper<Value>>; }; 但是这个解决方案似乎只能在 gcc 中编译,在 clang 和 msvc 中失败:https://godbolt.org/z/zzY7WvoEd clang 会报告错误:“隐式实例化未定义模板”,而 msvc 似乎无法专门化别名模板。 我在这里遗漏了什么,还是我遇到了编译器扩展? 如果类型repack也定义了C,则可以重新实现mapped_type类型特征,以便选择第二部分特化。假设类型特征仅与标准容器一起使用,这足以保证为关联容器选择专门化。 可以通过SFINAE或requires-clause添加约束。在这种情况下,首选前者与 C++11 标准兼容。 示例: namespace detail { template <template <typename> typename, typename, typename = void> struct repack {}; template <template <typename> typename Wrapper, template <typename...> typename C, typename T> struct repack<Wrapper, C<T>> { using type = C<Wrapper<T>>; }; template <template <typename> typename Wrapper, template <typename...> typename C, typename T, typename U> struct repack<Wrapper, C<T, U>, std::void_t<typename C<T, U>::mapped_type>> { using type = C<Wrapper<T>, Wrapper<U>>; }; } template <template <typename> typename Wrapper, typename C> struct repack : detail::repack<Wrapper, C> {}; template <template <typename> typename Wrapper, typename C> using repack_t = typename repack<Wrapper, C>::type;

回答 1 投票 0

当元组元素之一具有默认构造函数而另一个没有时,如何将构造函数参数转发到包含的元组

我正在尝试编写一个使用 std::tuple 来存储一堆可能具有不同类型的对象的类。如果元素都有带有一些参数的构造函数,我可以初始化元组...

回答 1 投票 0

使用虚拟结构重载函数与模板专业化

我正在重构一些 C++,并遇到一些用于区分重载函数的虚拟结构。我正在考虑用模板专业化来替换它,但想要完全

回答 1 投票 0

提取容器模板以存储不同类型

给定某种类型的容器作为输入,是否可以“提取”容器模板并将其实例化为不同类型?例如: 无效 f ( 自动& x ) {

回答 1 投票 0

函数结果的通用完美转发

我在尝试以通用方式完美转发函数结果时遇到了问题。 这里有两个提供结果的函数: Foo 提供FooAsTemporary() { 返回 Foo{}; } 富&

回答 1 投票 0

如何对类型对进行参数打包?

以下是参数包的使用示例: 模板 布尔 foo(A x) { 返回 (baz(x) || ...); } 我想做类似的事情,但是使用成对的类型。这是一个

回答 1 投票 0

可变参数模板参数的联合

给定类型 Ts 的可变列表...,我们可以创建一个联合对象来精确保存这些类型的联合(并且没有额外的数据)? 当然,这对于 std::variant 是可能的。然而,关键的

回答 1 投票 0

模板类型推导包含const吗?

我有: 模板 班级持有人 { T&举行; 民众: 支架(T&h) :举行(小时) {} 朋友 std::ostream& 运算符<<(std::

回答 1 投票 0

如何使tag_invoke CPO统一处理与元谓词/概念匹配的类型以及包装在reference_wrapper中的类型?

(我最感兴趣的是 c++17 解决方案,即使你看到我使用 std::unwrap_ref_decay;想象一下我已经在我的 C++17 代码中复制并粘贴了可能的实现。另一方面手,...

回答 1 投票 0

© www.soinside.com 2019 - 2024. All rights reserved.