结合多个类模板专长

时间:2018-06-29 22:55:59

标签: c++ c++11 templates c++14 variadic-templates

以下面的示例为例,凝聚模板专业化的最佳方法是什么,以便一个或两个指令足以定义所有特殊值?可变参数的,也许吗?

enum class PositiveDigit // Not necessarily sequential
{ One=1, Two, Three, Four, Five, Six, Seven, Eight, Nine };

// Base class template
template <std::underlying_type_t<PositiveDigit>>
struct IsNum
{ static constexpr bool aPrimeDigit = false; };

// Specialized class templates to define which positive digits are prime 
// HOW TO BEST COMBINE/CONDENSE THESE? VARIADIC?? Ideally, something like:
//    template <PositiveDigit::Two, PositiveDigit::Three, ……> ……   OR,
//    template <> …… (PositiveDigit::Two, PositiveDigit::Three, ……) ……   OR??
template <>
struct IsNum<static_cast<std::underlying_type_t<PositiveDigit>>(PositiveDigit::Two)>
{ static constexpr bool aPrimeDigit = true; };
template <>
struct IsNum<static_cast<std::underlying_type_t<PositiveDigit>>(PositiveDigit::Three)>
{ static constexpr bool aPrimeDigit = true; };
template <>
struct IsNum<static_cast<std::underlying_type_t<PositiveDigit>>(PositiveDigit::Five)>
{ static constexpr bool aPrimeDigit = true; };
template <>
struct IsNum<static_cast<std::underlying_type_t<PositiveDigit>>(PositiveDigit::Seven)>
{ static constexpr bool aPrimeDigit = true; };

int main() {
    // Note: It's perfectly okay to pass integers beyond the range of the
    //  enum class, they'll simply provide a false result
    IsNum<-5>::aPrimeDigit; // false
    IsNum<13>::aPrimeDigit; // false
    IsNum< 7>::aPrimeDigit; // true!
}

请假设enum必须保持强类型。现实世界中的问题enum class很大,潜在的专业领域很多,与数字或质数无关。这只是一个简单的例子。

这些类似的问题似乎无法解决当前的问题(除非我遗漏了一些东西):

2 个答案:

答案 0 :(得分:1)

您是否正在寻找类似的东西?

C ++ 17:

import std.stdio;


class CAdata{ string username;}



class Users{

  int age;
  CAdata[] info;



    this(){

      setNull();
    }


    void setNull(){
      age = 0;
      info ~= new CAdata();
    }
}

class CaStore{

    Users[] ccuser;

    this(){
        ccuser ~=  new Users();
    }       
}





void main()
{

    Users user1 = new Users();
    user1.age = 24;
    user1.info[0].username = "bob";

    Users user2 = new Users();
    user2.age = 24;
    user2.info[0].username = "alice";

    CaStore db = new CaStore();
    db.ccuser[0] = user1;
    db.ccuser[1] = user2;
}

或C ++ 14:

#include <type_traits>

template <auto Value, decltype(Value)... List>
struct value_in_list
    : public std::disjunction<std::bool_constant<Value==List>...> {};

template <std::underlying_type_t<PositiveDigit> N>
struct IsNum
{
    static constexpr bool aPrimeDigit =
        value_in_list<static_cast<PositiveDigit>(N),
            PositiveDigit::Two, PositiveDigit::Three,
            PositiveDigit::Five, PositiveDigit::Seven
        >::value;
};

答案 1 :(得分:0)

为了使可变参数模板有趣,我提出了一些解决方案。

它们两者都基于constexpr函数,该函数说明一个值是否在模板可变列表中(如aschepler的回答中的value_in_list一样,但这在C ++ 14中也有效)

template <typename T, T ... ts>
constexpr bool isInList (T const & t0)
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { false, ret |= t0 == ts... };

   return ret;
 }

第一个与aschepler的解决方案(+1)非常相似,并且不使用模板专门化。

template <std::underlying_type_t<PositiveDigit> I>
struct IsNum1
{ 
   static constexpr bool aPrimeDigit
      = isInList<PositiveDigit, PositiveDigit::Two, PositiveDigit::Three,
                 PositiveDigit::Five, PositiveDigit::Seven>
                    (static_cast<PositiveDigit>(I));
};

在我看来,这是比较简单的一种,但是如果您真的(真的!)想要通过模板专业化,则可以编写如下内容

template <std::underlying_type_t<PositiveDigit>, typename = std::true_type>
struct IsNum2
 { static constexpr bool aPrimeDigit = false; };

template <std::underlying_type_t<PositiveDigit> I>
struct IsNum2<I, std::integral_constant<bool, isInList<
   PositiveDigit, PositiveDigit::Two, PositiveDigit::Three,
   PositiveDigit::Five, PositiveDigit::Seven>
      (static_cast<PositiveDigit>(I))>>
 { static constexpr bool aPrimeDigit = true; };

以下是完整的编译示例

#include <type_traits>

enum class PositiveDigit
{ Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine };

template <typename T, T ... ts>
constexpr bool isInList (T const & t0)
 {
   using unused = bool[];

   bool ret { false };

   (void)unused { false, ret |= t0 == ts... };

   return ret;
 }

template <std::underlying_type_t<PositiveDigit> I>
struct IsNum1
{ 
   static constexpr bool aPrimeDigit
      = isInList<PositiveDigit, PositiveDigit::Two, PositiveDigit::Three,
                 PositiveDigit::Five, PositiveDigit::Seven>
                    (static_cast<PositiveDigit>(I));
};

template <std::underlying_type_t<PositiveDigit>, typename = std::true_type>
struct IsNum2
 { static constexpr bool aPrimeDigit = false; };

template <std::underlying_type_t<PositiveDigit> I>
struct IsNum2<I, std::integral_constant<bool, isInList<
   PositiveDigit, PositiveDigit::Two, PositiveDigit::Three,
   PositiveDigit::Five, PositiveDigit::Seven>
      (static_cast<PositiveDigit>(I))>>
 { static constexpr bool aPrimeDigit = true; };

int main ()
 {
   static_assert( false == IsNum1<-5>::aPrimeDigit, "!" );
   static_assert( false == IsNum1<13>::aPrimeDigit, "!" );
   static_assert(  true == IsNum1< 7>::aPrimeDigit, "!" );

   static_assert( false == IsNum2<-5>::aPrimeDigit, "!" );
   static_assert( false == IsNum2<13>::aPrimeDigit, "!" );
   static_assert(  true == IsNum2< 7>::aPrimeDigit, "!" );
 }