2017-11-07 12 views
1

2 가지 프로토콜을 처리 할 수있는 통신 클래스가 있습니다. 프로토콜은 열거 형 템플릿 변수에 의해 선택됩니다. 이제 2 개의 프로토콜 중 1 개는 2 바이트 값만 지원하고 다른 프로토콜은 4 바이트 값을 지원합니다. 통신은 템플릿 멤버 함수를 통해 수행됩니다. 클래스 전문화 (= 선택된 프로토콜)에 따라 2 바이트 또는 4 바이트를 사용하도록 static_assert를 변경하는 방법은 무엇입니까?템플릿 enum 매개 변수를 기반으로 동작 변경

#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 답을 올바른 것으로 선택할 수 있습니다. 그리고 Roy에게서 가장 많은 것을 배웠지 만 가능한 한 간단하게 유지하기 때문에 MM의 답을 골랐습니다.

+2

왜 궁극적으로 두 배 또는 (긴) 긴 정수를 부동 소수점으로 다운 캐스팅하는 경우 템플릿이 필요한가요? 어쩌면 그냥 float을 수락하고 호출자에게 필요한 경우 클래스를 사용할 때 그의 정밀도에 어떤 일이 일어날 지 궁금해하는 최종 컴파일러 경고를 허용하는 것이 좋습니다. –

+0

@MichaelRoy이 라이브러리는 Arduino 사용자를 대상으로합니다. 필자는 컴파일러 경고 (기본적으로 비활성화 됨)를 살펴 본다. 그러나 당신은 매우 유효한 포인트를 가지고 있습니다! 나는 프로그램의 디자인을 조사 할 것이다. – BMelis

+1

'((P == P1)? 2 : 4)'도 아마 괜찮을 것입니다. –

답변

4

(upvoted 모두 불구하고)이 여기에 ...이 접근하는 여러 가지 방법의 하나입니다

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>(), 
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. 
{ ... };