根据模板枚举参数更改行为

时间:2017-11-07 21:17:31

标签: c++ templates enums template-specialization

我有一个可以处理2种不同协议的通信类。该协议由枚举模板变量选择。 现在,2个协议中的1个仅支持2个字节的值,而另一个支持4个字节的值。 通过模板成员函数完成通信。如何更改static_assert所以它需要2或4个字节,具体取决于类的特化(=选择的协议)?

#include <iostream>
#include <math.h>

enum Protocol { P1, P2 };


template <Protocol P>
class Communicator {
  public:
    template <typename T>
    void communicate(T arg) {
      static_assert(sizeof(arg) <= sizeof(float), "argument size must be <= 4 bytes");
      float value = (float)arg;
      uint8_t length = sizeof(arg);  //length in bytes
      _communicate(value, length);
    }

    void _communicate(float f, uint8_t length) {
      std::cout << f;
    }
};

编辑:我可以选择1个答案为正确。虽然我从罗伊那里学到了很多东西,但我选择了MM的答案,因为它让事情变得尽可能简单。 (但两者都赞成)

2 个答案:

答案 0 :(得分:4)

有几种方法可以解决这个问题......这里有一个:

template<Protocol P>
size_t value_size();

template<> size_t value_size<P1>() { return 2; }
template<> size_t value_size<P2>() { return 4; }

// ... inside your other function
static_assert(sizeof(arg) <= value_size<P>(), 

答案 1 :(得分:2)

这是一种不同的方法

#include <iostream>
#include <math.h>
#include <cstdint>

// enum Protocol { P1, P2 };  // let's use types with traits instead.

struct P1
{
    constexpr static const int protocol_id = 1; 
                           //^^ or maybe use an enum 
                           // type, this may need refactoring
                           // to fit your code and style.
    using data_type = uint16_t;  //< or whatever your 2-byte datatype is.

    // can add more data traits and even static member functions here

    // you could also add protocol specific non-static data if you add a 
    // P1 data member to your Communicator class.

    // A struct with traits is a very good entry point for many compile-time
    // polymorphism techniques.
};

struct P2
{
    constexpr static const int protocol_id = 2;
    using data_type = uint32_t;  //< or whatever your 4-byte datatype is.
};


template <typename _Proto>
class Communicator {
  public:
      using data_type = typename _Proto::data_type;
      constexpr static const int proto_id = typename _Proto::protocol_id;

  public:
    void communicate(data_type arg) // we can use the trait from either P1 or P2
   {
      float value = (float)arg;
      uint8_t length = sizeof(data_type);  //length in bytes
      _communicate(value, length);
    }

    void _communicate(float f, uint8_t length) 
    {
      std::cout << f;
    }
};

这里是转换枚举的代码(如果那是你已经拥有的一个类。

enum protocol_t { p1, p2 };

template <protocol_t _p> struct Protocol {};

// simply derive the template specialization from the desired type
template <> struct Protocol<p1> : P1 {};
// simply derive the template specialization from the desired type
template <> struct Protocol<p2> : P2 {};

您也可以从P1,P2派生,以帮助组织代码。

struct P1
{
   // ... + specialized functions:
   void _communicate(value_type x) { ... }  // that you'll call from Communicator
   void _communicate(const value_type* begin, const value_type* end) { ... }
};

struct P2 { /* same thing */ };

template <typename _Proto>
class Communicator : _Proto // < can control visibility here.
{ ... };