模板元编程是一种元编程技术,其中编译器使用模板生成临时源代码,该代码由编译器与其余源代码合并然后编译。
C++ 模板与 OOD 困境 - 我怎样才能绕过实现“模板化类成员变量”之类的东西?
我试图使用模板来节省大量代码重复。 理想情况下,我想做一些类似的事情(我知道它的垃圾代码): 类注册表{ 民众: 模板 我试图使用模板来节省大量代码重复。 理想情况下,我想做一些类似的事情(我知道它的垃圾代码): class Registries { public: template<typename T> void AddToRegistry(T thing) { registry.push_back(thing); } template<typename T> std::vector<T>* GetRegistry<T>() { return ®istry(); } private: template<typename T> std::vector<T> registry; // auto-magically created vectors for each used type }; int main() { Registries registries; CoolThing thing1; NiceThing thing2; // ... Many N types registries.AddToRegistry(thing1); registries.AddToRegistry(thing2); std::vector<CoolThing>* cool_registry = registries.GetRegistry<CoolThing>(); std::vector<NiceThing>* nice_registry = registries.GetRegistry<NiceThing>(); } 它当然不起作用,因为我无法模板化类成员 - 不会为每种类型创建变量,并且这些函数不知道要返回哪个): 我可以这样做,但它们都会存储在静态内存中(不理想): class CoolThing { public: static std::vector<CoolThing> registry; }; class NiceThing { public: static std::vector<NiceThing> registry; }; class Registries { public: template<typename T> void AddToRegistry(T thing) { T::registry.push_back(thing); } } int main() { Registries registries; registries.AddToRegistry(CoolThing()); registries.AddToRegistry(NiceThing()); // ... Many N types } 我还在模板中尝试了 switch 和 if-else,但它们似乎不兼容: class CoolThing { public: const static ThingType TYPE = COOL; }; class NiceThing { public: const static ThingType TYPE = NICE; }; class Registries { public: template<typename T> void AddToRegistry(T thing) { switch (T::TYPE) { case ThingType::COOL: cool_registry.push_back(thing); return; case ThingType::NICE: nice_registry.push_back(thing); return; default: return; } } template<typename T> std::vector<T>* GetRegistry<T>() { if (T::TYPE == ThingType::COOL) { return &cool_registry; } else if (T::TYPE == ThingType::NICE) { return &nice_registry; } return nullptr; } private: std::vector<CoolThing> cool_registry; std::vector<NiceThing> nice_registry; // ... Many N types }; int main() { Registries registries; CoolThing thing1; NiceThing thing2; // ... Many N types registries.AddToRegistry(thing1); registries.AddToRegistry(thing2); std::vector<CoolThing>* = registries.GetRegistry<CoolThing>(); std::vector<NiceThing>* = registries.GetRegistry<NiceThing>(); } 我觉得我的选择是静态方式,或者编写一长串(20+类型)函数重载以添加到正确的注册表类型。 任何模板专家都知道替代方案吗? 非常感谢 您最可能寻找的是模板专业化。您可以在模板化定义上定义特定类型案例的行为。 class Regs { public: template<typename T> void AddRegister(T t) { ... } // Generic Case template<> void AddRegister<CoolThing>(CoolThing ct) { ... } // When T is CoolThing template<> void AddRegister<NiceThing>(NiceThing nt) { ... } // When T is NiceThing };
C++20 - 如何将模板参数包参数限制为“链”序列,例如F<A,B>、F<B,C>、F<C, D>?
假设我有两门课: 模板 类函子 {}; 模板 类模板 {}; 模板有
c++20 - 如何将模板参数包参数限制为“链”序列,例如F<A,B>、F<B,C>、F<C, D>?
假设我有两门课: 模板 类函子 {}; 模板 类模板 {}; 模板有
我有以下状态机示例,它使用枚举来专门化带有可变参数包的模板方法。当我通过
我正在寻找一种非递归的现代方法(至少可以使用 gcc 和 clang 进行编译)来查找可变参数包的第 𝑛 个元素。事实上,这似乎是一个解决方案,使用...
由于布尔类型模板函数中未使用参数,如何在 C++ 中拥有备用函数签名?
我的目标是有一个库提供我的函数增量的多个实例,基于唯一的定义以避免代码冗余: 模板 int 增量(int a, int b) { 如果
C++ constexpr 和 std::is_contant_evaluated 之间的交互
在 CppNow 演讲中(Don’t constexpr All the Things - David Sankel),它使用以下函数作为示例: constexpr int f() { if constexpr (std::is_constant_evaluated()) { // 慢
我正在尝试构建一个类模板,其中一个静态方法需要在模板参数中指定 typedef。 目标是指定一个像这样的 typedef typedef foobar = void __stdcall ...
我编写了以下在编译时使用字符串的代码: 模板 结构体 CnstString { 模板 使用push_back = CnstString 我编写了以下代码以在编译时使用字符串: template<char... Chars> struct CnstString { template<char... Aped> using push_back = CnstString<Chars..., Aped...>; constexpr static char value[] = {Chars...}; }; 我这样使用就可以了: #include <iostream> using str = CnstString<'H', 'e', 'l', 'l', 'o', '\0'>; int main() { std::cout << str << std::endl; return 0; // it will output "Hello" } 我想做的是使用递归模板结构体,在编译时拼接上面代码给出的字符串,并在递归终点处向数组追加一个'\0'。 我写这段代码的原因是因为我想多次连接同一个字符串。显然我不能像"Hello""Hello"那样将相同的字符串连接在一起。 递归模板结构如下所示: template<int N, typename Str> struct RepeatStr { using ret = RepeatStr<N-1, Str>; // this is an error, I don't know how to pass parameters }; template<typename Str> struct RepeatStr<-1, Str> { using ret = Str::push_back<'\0'>; }; 但是,我发现我不知道如何使用Str中的字符向自身追加字符。 有什么问题吗?或者它根本不可能在编译时完成? 您需要在 using 声明中添加关键字 template 来告诉编译器 push_back 使用模板。 template<int N, typename Str> struct RepeatStr { using ret = RepeatStr<N-1, Str>; }; template<typename Str> struct RepeatStr<-1, Str> { //--------------------vvvvvvvv------------------->works now using ret = Str:: template push_back<'\0'>; }; 工作演示
C++11:用另一个 constexpr char 数组初始化 constexpr char 数组
我想用另一个 constexpr char [] 成员初始化 constexpr char[] 成员。可以用C++11或以上版本实现吗? #包括 结构基{ static constexpr char Va...
我正在尝试完成模板元编程练习文本。但是,当我尝试部分特化非类型模板参数时,我会遇到不同的行为。 我定义了一个编译时向量...
我正在用 C++ 编写模板元编程代码,以生成用于嵌入式编程目的的查找表(缺少 FPU)。我一直在使用 MSVC 进行原型设计。 当尝试生成最终的
模板 结构体有_类型; 模板 结构 has_type> : std::false_type {}; 模板 template<typename T, typename Tuple> struct has_type; template<typename T> struct has_type<T, std::tuple<>> : std::false_type {}; template<typename T, typename U, typename... Ts> struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {}; template<typename T, typename... Ts> struct has_type<T, std::tuple<T, Ts...>> : std::true_type {}; template<typename T, typename Tuple> using tuple_contains_type = typename has_type<T, Tuple>::type; using FooTuple = std::tuple<int, float, bool>; struct Foo : FooTuple { using TupleType = FooTuple; }; int main() { // this compiles if constexpr (tuple_contains_type<float, Foo::TupleType>::value) { // ... } // this does not if constexpr (tuple_contains_type<float, Foo>::value) { // ... } return 0; } 第一种情况可以编译,第二种情况则不能。我针对失败案例收到的错误是: error C2794: 'type': is not a member of any direct or indirect base class of 'has_type<float,Foo>' note: see reference to alias template instantiation 'tuple_contains_type<float,Foo>' being compiled error C2938: 'tuple_contains_type' : Failed to specialize alias template error C2039: 'value': is not a member of '`global namespace'' error C2059: syntax error: ')' error C2143: syntax error: missing ';' before '{' 到期贷记; has_type 和 tuple_contains_type 的模板来自:How do I find out if a tuple contains a type? 问题是struct has_type<float, Foo>没有定义。模板实例化不会调用重载查找和转换。
我有以下代码: #包括 #包括 #包括 #包括 #包括<...
我有一个像这样的参数类: 模板 类参数 { 值 v; ... }; 我有一个参数包类: 模板 班级
我正在尝试创建一个编译时间矩阵作为模板参数 模板 结构体CTestMatrix { constexpr std::tuple GetData() { 返回 TMA...
让我们考虑以下情况,我正在编写库,而不是带有成本的运行时多态性,但与所有声明都有清晰可见的接口,我选择通用程序...
我正在尝试模拟std::any,我的想法是使用基类指针指向不同类型的模板派生类,来实现存储不同类型数据的功能,比如...
如何定义一个 C++ 概念来检查给定的模板类型参数是否是pair的顺序容器<T, T>
如何定义 C++ 概念来检查给定模板类型参数是否是顺序容器或成对范围(例如向量>. 让我们说出
我有一个模板类,它使用模板参数(std::enable_if_t)来限制主模板参数,如下所示: 模板 我有一个模板类,它使用模板参数(std::enable_if_t)来限制主模板参数,如下所示: template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>> class Foo { void foo(); } template<typename T> void Foo<T>::foo() {} // compiler complains 我知道我可以使用 static_assert 解决这个问题,但我想知道在这种情况下正确的方法是什么。 我想我可以简单地再次复制两个模板参数,但这对我来说似乎很奇怪。 您必须添加第二个模板参数: // ..................vvvvvvvvvv template<typename T, typename U> void Foo<T, U>::foo() {} // compiler doesn't complains anymore // ........^^ 或者,也许更好,在类中实现该方法: template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>> class Foo { void foo() {} // .......^^^ }; 无论如何...考虑到您使用 SFINAE 限制(第一个)参数类型的方法有一个缺陷:您正在对第二个模板参数的 default 值进行操作,因此可以通过显式绕过它在实例化中包括第二个模板参数。 我的意思是...当 T 是算术时,您可以正确定义类型: Foo<int> f; // compile 并且当 T 不是算术时正确地无法编译: Foo<void> f; // compilation error 但是,当您显式包含第二个模板参数时,它会编译(当 T 不是算术时): Foo<void, void> f; // compiles!!! 我想你不会 Foo<void, void> 进行编译。 为了避免这个问题,可以在等号左边使用SFINAE,删除模板参数,而不是默认值。 例如,你可以写: template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, bool> = true> class Foo { void foo() {} }; 这样,当第一个模板参数不是算术类型时,您可以确定没有人可以实例化 Foo 对象。 这个解决方案有一个小问题(或者可能没有……取决于您的期望):您可以通过同一个 T 参数定义两个不同的类。 我的意思是...你可以定义: Foo<int> f0; Foo<int, true> f1; // same type as f0 Foo<int, false> f2; // different type from f0 and f1 为了避免这种情况,对于第二个参数的类型,可以使用接受单个值的类型。例如:std::nullptr_t template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, std::nullptr_t> = nullptr> class Foo { void foo() {} }; 现在,您可以拥有一个 Foo<int>,它是 Foo<int, nullptr> 的简写,但不是第二个模板参数不同的类。 您可以在类中将 SFINAE 设为嵌套模板,以限制函数的类型。 SFINAE 作为嵌套模板: // class declaration template <typename T> class Foo; // class definition template <typename T> class Foo { void foo(); template <typename U, typename = std::enable_if_t<std::is_arithmetic_v<U> > > void somefunction(U val); // function declaration } // somefunction definition template <typename T> template <typename U, typename> void Foo<T>::somefunction(U val) {// *** code here *** //;} 我通常使用这种语法,因为编译时错误消息至少在某种程度上是可读的: msvc:main.cpp(21,22): error C2079: 's' uses undefined class 'Foo<std::string,void>' 海湾合作委员会:main.cpp:21:22: error: aggregate ‘Foo > s’ has incomplete type and cannot be defined #include <type_traits> #include <iostream> #include <string> template <typename type_t, typename enable_t = void> class Foo; template <typename type_t> class Foo<type_t, std::enable_if_t<std::is_arithmetic_v<type_t>>> { public: void foo() { std::cout << "foo\n"; } }; int main() { Foo<int> f; Foo<std::string> s; f.foo(); return 0; }