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

Change behavior based on template enum parameter

本文关键字:参数 枚举      更新时间:2023-10-16

我有一个可以处理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的答案,因为它使事情尽可能简单。(虽然两者都投了赞成票)

有几种方法可以解决这个问题...这是其中之一:

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>(), 

这是一种不同的方法

#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.
{ ... };