天道酬勤,学无止境

多个枚举值的一种模板特化(One template specialization for several enum values)

问题

通常,如果我想通过枚举创建一个模板化(数据)类,我会写这样的东西

enum class Modes : int
{
    m1 = 1,
    m2 = 2,
    m3 = 3
};

template <Modes M>
class DataHolder
{
};

template<>
class DataHolder<Modes::m1>
{
    public: int a = 4;
};

然后,如果我希望Modes::m1专业化与Modes::m2的专业化相同,我将再次编写相同的专业化。 有没有办法为多个枚举值编写一个专业化? 我已经用 SFINAE 尝试过,但我没有成功。

template <Modes M, typename = void>
class DataHolder
{
};

template<Modes M, typename = typename std::enable_if<M == Modes::m1 || M == Modes::m2>::type>
class DataHolder
{
    public: int a = 4;
};

这不编译。 特别是,在我想继续对Modes::m3进行不同的专业化之后。 我在 SO 上尝试了许多类似的解决方案,但似乎没有任何解决问题的方法。

回答1

您应该将enable_if放在与默认值匹配的DataHolder的显式特化中。 如果enable_if的条件评估为true则将选择专业化。

template <Modes M, typename = void>
class DataHolder
{
};

template<Modes M>
class DataHolder<M, typename std::enable_if<M == Modes::m1 || M == Modes::m2>::type>
{
    public: int a = 4;
};

int main()
{   
    DataHolder<Modes::m1> a; a.a;
    DataHolder<Modes::m3> b; /* b.a; */
}

godbolt.org 上的实时示例

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 仅针对具有枚举非类型模板参数的 C++ 模板函数的特化(Specializations only for C++ template function with enum non-type template parameter)
    问题 这个问题与这个问题有关,只是我没有处理 typename 模板参数,而是尝试使用枚举非类型模板参数。 在非类型模板参数的情况下,是否有可能有一个只有专业化的模板化(类成员函数),没有通用(工作)定义? 通过在类主体中声明并仅提供专业化,我能够使一个版本正常工作,但是任何使用未定义模板参数的误用调用都不会在链接之前产生错误。 更糟糕的是,缺少的符号暗指枚举的整数值而不是其名称,因此其他开发人员会感到困惑。 我能够从引用的问题中获得BOOST_STATIC_ASSERT技术,仅适用于 typename 模板参数。 这段代码演示了这个想法。 我不想编译CAT -version 调用: #include <iostream> #include <boost/static_assert.hpp> // CLASS HEADER FILE: struct foo_class { enum AllowedTypes { DOG, CAT }; template <AllowedTypes type> void add_one_third( double bar ) const { BOOST_STATIC_ASSERT_MSG(sizeof(type)==0, "enum type not supported."); } }; // CLASS SOURCE FILE template<>
  • gcc 找不到模板特化(gcc does not find template specialization)
    问题 我的网络代码使用模板特化来序列化不能简单复制的类型。 我定义了一个通用模板 template<typename T> struct TypeHandler 处理可以通过简单的memcpy传输的所有类型,然后我为所有其他类型定义特化。 现在的问题是我有一个具有多个此类专业化的文件,如果我使用 Visual Studio 编译代码,一切正常。 但是对于 gcc,该文件中的所有模板特化都会被使用,除了 template<> struct TypeHandler<uint32_t> 哪个可变长度对整数进行编码以节省空间。 所有 TypeHandler 版本的命名空间都是相同的,它们甚至在同一个文件中。 但出于某种原因,gcc 决定使用通用版本,我真的不知道为什么。 编辑: 似乎 gcc 使用了来自另一个项目的 TypeHandler 实例化,该项目与之链接但没有专门针对 uint32_t 的项目,即使它传输 uint32_t 字段。 虽然 GCC 没有给我任何错误。 我如何告诉 gcc 像 Visual Studio 一样使用专业化? 编辑2: 设法生成了一个 SSCCE http://netload.in/dateiz3R4eTVqi3/src.tar.gz.htm 这里的错误是相反的但是很好。 EDIT3:固定文件大小:http://netload.in
  • 是否可以使用成员枚举专门化模板?(Is it possible to specialize a template using a member enum?)
    问题 struct Bar { enum { Special = 4 }; }; template<class T, int K> struct Foo {}; template<class T> struct Foo<T,T::Special> {}; 用法: Foo<Bar> aa; 无法使用 gcc 进行编译 4.1.2 它抱怨使用T::Special进行 Foo 的部分专业化。 如果Special是一个类,那么解决方案就是在它前面加上一个类型名。 枚举(或整数)是否有与它等效的东西? 回答1 由于 Prasoon 所解释的 C++ 不允许这样做,因此另一种解决方案是使用EnumToType类模板, struct Bar { enum { Special = 4 }; }; template<int e> struct EnumToType { static const int value = e; }; template<class T, class K> //note I changed from "int K" to "class K" struct Foo {}; template<class T> struct Foo<T, EnumToType<(int)T::Special> > { static const int enumValue = T::Special
  • 类模板的显式特化的定义应该放在 C++ 的什么地方?(Where should the definition of an explicit specialization of a class template be placed in C++?)
    问题 根据 [temp.spec]/5: 对于给定的模板和给定的模板参数集, ... 一个明确的专业化最多只能在一个程序中定义一次(根据 [basic.def.odr]),并且 ... 类模板的显式(完全)特化的定义不能放在标题中(否则每个包含此标题的翻译单元中都有一个定义,因此整个程序中将有多个定义)。 此外,作为另一个证据,[basic.def.odr]/12(下面引用的块)中列出的实体不包含类模板的完整特化。 相反,包含“未指定某些模板参数的模板特化”。 一个类类型、枚举类型、带有外部链接的内联函数([dcl.inline])、带有外部链接的内联变量([dcl.inline])、类模板、非静态函数模板,可以有多个定义,概念 ([temp.concept])、类模板的静态数据成员、类模板的成员函数或未指定某些模板参数的模板特化([temp.spec]、[temp.class.spec])在程序中,前提是每个定义出现在不同的翻译单元中,并且定义满足以下要求。 但是,如果我将定义放在源文件中并将其声明保留在标题中,例如, // "a.h" template <typename T> struct S {}; template <> struct S<int>; // declaration // "a.cpp" #include "a.h" template <> struct S
  • python编程英语词汇大全-编程常用英语词汇大全
    很实用的编程英语词库,共收录一千五百余条词汇。 第一部分: application 应用程式 应用、应用程序 application framework 应用程式框架、应用框架 应用程序框架 architecture 架构、系统架构 体系结构 argument 引数(传给函式的值)。叁见 parameter 叁数、实质叁数、实叁、自变量 array 阵列 数组 arrow operator arrow(箭头)运算子 箭头操作符 assembly 装配件 assembly language 组合语言 汇编语言 assert(ion) 断言 assign 指派、指定、设值、赋值 赋值 assignment 指派、指定 赋值、分配 assignment operator 指派(赋值)运算子 = 赋值操作符 associated 相应的、相关的 相关的、关联、相应的 associative container 关联式容器(对应 sequential container) 关联式容器 atomic 不可分割的 原子的 attribute 属性 属性、特性 audio 音讯 音频 A.I. 人工智慧 人工智能 background 背景 背景(用於图形着色) 後台(用於行程) backward compatible 回溯相容 向下兼容 bandwidth 频宽 带宽 base class
  • C++ - 函数模板特化的目的是什么? 什么时候使用?(C++ - What is the purpose of function template specialization? When to use it?)
    问题 学习C++,遇到了函数模板。 本章提到了模板专业化。 template <> void foo<int>(int); void foo( int ); 当您可以使用第二个时,为什么要专门化? 我认为模板应该概括。 当您只能使用常规函数时,将函数专门用于特定数据类型有什么意义? 显然,模板特化的存在是有原因的。 应该什么时候使用? 我读过 Sutter 的“为什么不专门化……”文章,但我需要更多外行版本,因为我只是在学习这些东西。 回答1 主要区别在于,在第一种情况下,您为编译器提供特定类型的实现,而在第二种情况下,您提供的是不相关的非模板化函数。 如果你总是让编译器推断类型,非模板化函数将被编译器优先于模板,并且编译器将调用自由函数而不是模板,因此提供与参数匹配的非模板化函数将具有在大多数情况下,专业化的效果相同。 另一方面,如果在任何地方提供模板参数(而不是让编译器推断),那么它只会调用通用模板并可能产生意想不到的结果: template <typename T> void f(T) { std::cout << "generic" << std::endl; } void f(int) { std::cout << "f(int)" << std::endl; } int main() { int x = 0; double d = 0.0; f(d); //
  • 在专门化之前使用模板?(Using a template before it's specialized?)
    问题 我发现如果您使用包装模板使用它,您可以在第一次使用模板后对其进行专门化。 简单的例子: #include <iostream> template<typename T> const char* templateImpl(); template<typename T> const char* templateGetter() { return templateImpl<T>(); } struct S{}; int main(){ std::cout << templateGetter<S>() << std::endl; return 0; } template<> const char* templateImpl<S>(){ return "S"; } 这适用于每个编译器 - 我并不惊讶 MSVC 编译它,因为它以不同的方式处理模板,但 GCC 和 clang 也允许它。 我认为标准要求在第一次使用之前进行专业化,在这种情况下,这意味着在 main 之前并期望他们报告错误。 我错过了什么,这个代码标准符合吗? 澄清一下,如果我在 main 中将templateGetter<S>更改为templateImpl<S> ,则程序将不会编译,并显示我期望的错误消息: main.cpp:14:29: 错误:实例化后“const char* templateImpl() [with T
  • 具有常量值的 C++ 模板特化(C++ Template Specialization with Constant Value)
    问题 给定一个模板参数的数值常量,是否有一种直接的方法来定义 C++ 模板类的部分特化? 我正在尝试为某些类型的模板组合创建特殊的构造函数: template <typename A, size_t B> class Example { public: Example() { }; A value[B]; }; template <typename A, 2> class Example { public: Example(b1, b2) { value[0] = b1; value[1] = b2; }; }; 此示例无法编译,在第二个定义中的Expected identifier before numeric constant返回错误Expected identifier before numeric constant 。 我已经看过这里和其他地方的一些例子,但大多数似乎都围绕着专门研究类型而不是常数。 编辑: 寻找一种方法来编写有条件使用的构造函数,其功能如下: template <typename A, size_t B> class Example { public: // Default constructor Example() { }; // Specialized constructor for two values Example<A,2>(A b1, A b2
  • C++ template metaprogram(元编程)
    metaprogramming含有“对一个程序进行编程”的意思。换句话说,编程系统将会执行我们所写的代码,来生成新的代码,而这些新代码才真正实现了我们所期望的功能。 通常而言,metaprogramming这个概念意味着一种反射的特性:metaprogramming组件只是程序的一部分,而且它也只生成一部分代码或者程序。 我们为什么需要metaprogramming呢?和大多数程序设计技术一样,使用metaprogramming的目的是为了实现更多的功能,并且使花费的开销更小,其中开销是以:代码大小、维护的开销等来衡量的。另一方面,metaprogramming的最大特点在于:某些用户自定义的计算可以在程序翻译期进行, 而这通常都能够在性能(因为在程序翻译期所进行的计算通常都可以被优化)或者接口简单性(一个metaprogram通常都要比它所扩展的程序简短)方面带来好处;甚至为两方面同时带来好处。 Metaprogram的第一个实例 在1994年C++标准委员会的一次会议上,ErwinUnruh提出了:可以使用模板来在编译期进行某些计算。于是,他写了一个用于产生素数的程序。其中特别的是:生成素数的计算是编译器在编译期执行的,而不是在运行期执行。最后,尽管这个程序并不是严格可移植的(因为错误信息没有标准化),但是该程序表明了:模板实例化机制是一种基本的递归语言机制
  • 具有多个模板参数的 C++ 单模板特化(C++ single template specialisation with multiple template parameters)
    问题 你好! 我只想专注于两种模板类型中的一种。 例如template <typename A, typename B> class X应该对单个函数X<float, sometype>::someFunc()有一个特殊的实现。 示例代码: 主文件: #include <iostream> template <typename F, typename I> class B { public: void someFunc() { std::cout << "normal" << std::endl; }; void someFuncNotSpecial() { std::cout << "normal" << std::endl; }; }; template <typename I> void B<float, I>::someFunc(); 主.cpp: #include <iostream> #include "main.h" using namespace std; template <typename I> void B<float, I>::someFunc() { cout << "special" << endl; } int main(int argc, char *argv[]) { B<int, int> b1; b1.someFunc(); b1
  • 带指针的 C++ 类模板特化(C++ class template specialization with pointers)
    问题 我有以下格式的树结构: template <typename DataType> class Tree { DataType *accessData() { return data; } Tree *child1, *child2; DataType *data; }; template <typename DataType> class Root : public Tree<DataType> { // root provides storage of nodes; when it goes out of scope, the // entire tree becomes invalid MemoryPool<Tree> nodeStorage; MemoryPool<DataType> dataStorage; }; 我在我的程序中使用了这个模板的各种实例。 它运作良好。 然而,一个实例使用一个DataType ,它只是一个枚举(所以它与指针的大小相同!)并且因为速度是必不可少的(在构建树时和访问时),我宁愿有此实例化直接使用枚举而不是指针。 我希望代码看起来如何的示例(不严格): Tree<BigClass> *foo = ...; foo->accessData()->doBigClassThings(); Tree<int> *bar = ...; int x =
  • 双模板方法的部分特化失败(Partial specialization of double-templated method fails)
    问题 有模板类List。 template <typename Point> class List { public: template <const unsigned short N> void load ( const char *file); ... }; template <typename Point> template <const unsigned short N> void List <Point>::load ( const char *file) } 如何为 N=2 专门化方法负载? 此代码无效... template <typename Point> void List <Point> <2>::load ( const char *file) { } 而且这段代码也不起作用。 template <typename Point> void List <Point> ::load <2> ( const char *file ) { } Error 3 error C2768: 'List<Point>::load' : illegal use of explicit template arguments 66. Error 5 error C2244: 'List<Point>::load' : unable to match function
  • 通过模板模板参数使用枚举标记对象(Tagging objects using enums via template-template parameters)
    问题 我想使用模板的 enum 参数来限制第二个参数,一个类,进而将 enum 的一个成员作为参数,因为它是模板化参数。 在代码中,我希望它看起来像: CObject<EObjectTag, CSubObject<EObjectTag::CAT_A>> cObject; 但是,这应该有效: CObject<EObjectTag, CSubObject<ENotAnObjectTag::CAT_OTHER>> cObject; 应该失败,因为ENotAnObjectTag::CAT_OTHER是不是一个元素EObjectTag 。 我对此的实现(尝试)如下,并在编译期间(在 gcc 版本 4.9.2(Ubuntu 4.9.2-10ubuntu13)上)出现错误消息: source.cc:16:45: 错误: 'SUBOBJECT_TAG' 未在此范围内声明 struct CObject> #include <iostream> #include <typeinfo> enum class EObjectTag {CAT_A, CAT_B, CAT_OTHER}; // CSubObject template<class OBJECT_TAG_T, OBJECT_TAG_T OBJECT_TAG> struct CSubObject { OBJECT_TAG_T m_tTag =
  • 具有多个模板参数包的部分模板特化(Partial template specialization with multiple template parameter packs)
    问题 继续我的可变参数模板世界之旅,我遇到了另一个问题。 假设有以下模板类: template < typename T > struct foo { //default implementation }; 可以将它部分专门用于可变参数模板实例,如下所示: template < template < typename ... > class T, typename ...Args > struct foo< T< Args... > > { //specialized implementation }; 这样, foo< int >将对应于默认实现,而foo< std::tuple< int, char > >将对应于专门的实现。 然而,当使用多个模板参数时,事情变得更加复杂。 例如,如果我们有以下模板类 template < typename T, typename U > struct bar {}; 我们想像对foo所做的那样部分地专门化它,我们不能这样做 template < template < typename ... > class T, typename ...TArgs, template < typename ... > class U, typename ...UArgs > struct bar< T< TArgs... >, U< UArgs... > >
  • 匹配多种类型以进行模板特化解析(match multiple types for template specialization resolution)
    问题 简单地忽略正常函数重载将更好地服务于这个例子的事实。 它仅作为学习模板编程的一种方式。 话虽如此,欢迎您评论使用函数重载与函数模板专业化相比的好处/差异(尽管这可能值得自己提出问题)。 考虑以下示例: template <typename T> inline void ToString(T value, char* target, size_t max_size ); template <> inline void ToString<float>(float value, char* target, size_t max_size) { snprintf( target , max_size , "%f" , value); } template <> inline void ToString<double>(double value, char* target, size_t max_size) { snprintf( target , max_size , "%f" , value); } 有没有办法只编写一个匹配float和double类型的特化? 基本上,我设想为模板类型编写一个模板特化,该模板类型将同时匹配float和double (作为一种“float 或 double”类型匹配器),但我不确定这是否适用于 C++。 也就是说
  • 多个类型名称的部分模板特化(Partial template specialization for more than one typename)
    问题 在下面的代码中,我想考虑具有void返回的函数( Op )而不是被视为返回true 。 类型Retval和Op的返回值始终匹配。 我无法使用此处显示的类型特征进行区分,并且由于其他模板变量Op和Args的存在,尝试基于Retval创建部分模板特化失败。 如何在模板特化中只特化一些变量而不会出错? 有没有其他方法可以根据Op的返回类型改变行为? template <typename Retval, typename Op, typename... Args> Retval single_op_wrapper( Retval const failval, char const *const opname, Op const op, Cpfs &cpfs, Args... args) { try { CallContext callctx(cpfs, opname); Retval retval; if (std::is_same<bool, Retval>::value) { (callctx.*op)(args...); retval = true; } else { retval = (callctx.*op)(args...); } assert(retval != failval); callctx.commit(cpfs); return retval; } catch
  • Clang 无法在模板类特化中编译模板函数,它具有与模板声明不同的返回类型*(Clang fails to compile template function in a template class specialization, which has *distinct return type* from the template declaration)
    问题 以下函数derefItemX()在 GCC 4.8-5.3 上编译得很好,但在 CLang 3.8 上失败: //! Accessory Operations - template argument depended wrappers template<bool SIMPLE> // For Nodes / non-scoped storage struct Operations { //! \brief Defererence wrapped or direct iterator //! //! \param iel IItemXT& - iterator to be dereferenced //! \return ItemT& - resulting reference template<typename IItemXT> constexpr static auto& derefItemX(IItemXT& iel) { static_assert(is_base_of<std::forward_iterator_tag, typename IItemXT::iterator_category>::value , "derefItemX(), IItemXT must be a forward iterator type"); return **iel; //
  • 模板特化与类型萃取
    1_2.从案例中理解什么是模板特化1_2 1.1、本课程内容是用来干嘛的 (1)3.2主要讲了顺序容器,3.3讲了泛型算法,都是使用STL所必须掌握的 (2)本课程讲的特化和萃取,是STL内部实现所需要的,属于深度技术 (3)下个课程3.5会继续讲剩余的其他容器 (4)普通函数的优先级比特化函数高。错 优先级一样,但是在普通函数放在特化函数后面时,会函数重载,所以会执行普通函数。特化函数放在后面时,会将普通函数重载掉,就会执行特化函数。 1.2、通过一个案例理解模板特化 (1)案例前奏:写一个add函数库,可以适用于各种数据类型。结论是模板比函数重载好用。 (2)案例:写一个GreaterThan函数,可以对比各种数据类型的大小。 (3)特殊要求:int等比较数值大小,但string类型对比时,不比较字典序,而是以字符串长短来比较 1.3、模板特化总结 (1)模板特化有点类似于函数重载,而且都是编译链接时确定,而非运行时确定的。 (2)特化,specialize,就是让模板参数T在某个具体类型时可以特殊化指定处理 (3)特化的模板声明,前面一般是template<> 3.偏特化和全特化 3.1、全特化与偏特化概念 (1)全特化,特化原模板的所有模板类型为具体类型 (2)偏特化,又叫局部特化,特化原模板的部分类型,或部分特化原模板的类型 (3)全特化比较简单,本节即可全部解决
  • 专用模板类的静态成员初始化(static member initialization for specialized template class)
    问题 class A { }; template <typename A, int S> class B { public: static int a[S]; B() { a[0] = 0; } }; template<> int B<A, 1>::a[1]; int main() { B<A, 1> t; t; } 它在GCC 4.1下编译,但不链接: static.cpp:(.text._ZN1BI1ALi1EEC1Ev[B<A, 1>::B()]+0x5): undefined reference to `B<A, 1>::a' 如果可能的话,我宁愿保持专门的初始化,因为该数组保存了一些特定于该类型的数据。 回答1 对于静态成员专业化,如果不初始化成员,则将其视为专门化声明,即表示“哦,不要在主模板上实例化该成员,因为在其他地方有专门化的定义”。 应该提到的是,该定义应出现在.cpp文件中(否则,您将获得相反的结果:多个定义),并且没有初始化程序的声明仍应放在头文件中。 现在正确的语法的确以下内容,它不应该出现在头文件,但在.cpp文件 template<> int B<A, 1>::a[1] = { }; 以下内容仍应出现在头文件中: template<> int B<A, 1>::a[1]; 这将用作专业化声明。 由此可见,您无法专门化仅具有默认构造函数且不可复制的成员
  • 部分模板特化有什么问题?(What is wrong with partial template specialization?)
    问题 我正在编写一个带有一个类型参数和一个布尔值的模板化类,这是代码: template<class T, bool p = true> class A { private: T* ptr; public: A(); }; template<class T> A<T,true>::A() { ptr = 0xbaadf00d; } int main() { A<int> obj; A<int, false> o; return(0); } 我收到这些编译错误: Error 1 error C3860: template argument list following class template name must list parameters in the order used in template parameter list tst.cpp 15 Error 2 error C2976: 'A<T,p>' : too few template arguments tst.cpp 15 我究竟做错了什么? 或者是否出于某种原因禁止部分专门化非类型参数? 同时,如果我在 if 语句中使用布尔参数,则会收到以下警告: Warning 1 warning C4127: conditional expression is constant 所以我应该为这种事情做专业化