티스토리 뷰

다음은 # 3과 # 4 사이에있는 해결책입니다. 어쩌면 정말 유용한 지 확실하지 않은 영감을 줄 수도 있습니다.

인터페이스 기본 클래스와 가상 디스패치를 ​​사용하는 대신 "코덱"코드를 관련없는 특성 구조에 넣을 수 있습니다.

struct AnyFooCodec
{
    static size_t serialize(const Any&, char*)
        {
                // ...
                    }
                    
                        static Any deserialize(const char*, size_t)
                            {
                                    // ...
                                        }
                                        
                                            static bool is_trivially_serializable()
                                                {
                                                        // ...
                                                            }
                                                            };
                                                            
                                                            struct AnyBarCodec
                                                            {
                                                                static size_t serialize(const Any&, char*)
                                                                    {
                                                                            // ...
                                                                                }
                                                                                
                                                                                    static Any deserialize(const char*, size_t)
                                                                                        {
                                                                                                // ...
                                                                                                    }
                                                                                                    
                                                                                                        static bool is_trivially_serializable()
                                                                                                            {
                                                                                                                    // ...
                                                                                                                        }
                                                                                                                        };
                                                                                                                        

그런 다음 이러한 특성 유형을 유형 목록에 넣을 수 있습니다. 여기서는 a std::tuple사용 합니다.

typedef std::tuple<AnyFooCodec, AnyBarCodec> DispatchTable;

이제 n 번째 유형 특성을 주어진 펑터에 전달하는 일반 디스패치 함수를 작성할 수 있습니다.

template <size_t N>
struct DispatchHelper
{
    template <class F, class... Args>
        static auto dispatch(size_t type, F f, Args&&... args)
            {
                    if (N == type)
                                return f(typename std::tuple_element<N, DispatchTable>::type(), std::forward<Args>(args)...);
                                        return DispatchHelper<N + 1>::dispatch(type, f, std::forward<Args>(args)...);
                                            }
                                            };
                                            
                                            template <>
                                            struct DispatchHelper<std::tuple_size<DispatchTable>::value>
                                            {
                                                template <class F, class... Args>
                                                    static auto dispatch(size_t type, F f, Args&&... args)
                                                        {
                                                                // TODO: error handling (type index out of bounds)
                                                                        return decltype(DispatchHelper<0>::dispatch(type, f, args...)){};
                                                                            }
                                                                            };
                                                                            
                                                                            template <class F, class... Args>
                                                                            auto dispatch(size_t type, F f, Args&&... args)
                                                                            {
                                                                                return DispatchHelper<0>::dispatch(type, f, std::forward<Args>(args)...);
                                                                                }
                                                                                

이것은 적절한 특성을 찾기 위해 선형 검색을 사용하지만 약간의 노력으로 적어도 이진 검색으로 만들 수 있습니다. 또한 컴파일러는 가상 디스패치가 없기 때문에 모든 코드를 인라인 할 수 있어야합니다. 아마도 컴파일러는 기본적으로 스위치로 전환 할만큼 똑똑 할 수도 있습니다.

실제 예 : http://coliru.stacked-crooked.com/a/1c597883896006c4

-------------------

유형을 전달하여 오버로드를 선택하는 태그 디스패치가 효율적입니다. std라이브러리는 일반적으로 반복기의 알고리즘에이를 사용하므로 반복기 범주에 따라 구현이 다릅니다.

유형 ID 목록이있을 때 연속적인지 확인하고 점프 테이블을 작성합니다.

이것은 당면한 작업을 수행하는 함수에 대한 포인터 배열입니다.

C ++ 11 이상으로 작성하는 것을 자동화 할 수 있습니다. 런타임 스위치처럼 작동 하기 때문에 매직 스위치 라고 부르며 런타임 값을 기반으로 컴파일 시간 값이있는 함수를 호출합니다. 람다로 함수를 만들고 그 안에 매개 변수 팩을 확장하여 몸체를 다르게합니다. 그런 다음 전달 된 함수 객체로 디스패치합니다.

이를 작성하면 직렬화 / 역 직렬화 코드를 "유형 안전"코드로 이동할 수 있습니다. 특성을 사용하여 컴파일 타임 인덱스에서 유형 태그로 매핑하거나 인덱스를 기반으로 오버로드 된 함수로 디스패치합니다.

다음은 C ++ 14 매직 스위치입니다.

template<std::size_t I>using index=std::integral_constant<std::size_t, I>;

template<class F, std::size_t...Is>
auto magic_switch( std::size_t I, F&& f, std::index_sequence<Is...> ) {
  auto* pf = std::addressof(f);
    using PF = decltype(pf);
      using R = decltype( (*pf)( index<0>{} ) );
        using table_entry = R(*)( PF );
        
          static const table_entry table[] = {
              [](PF pf)->R {
                    return (*pf)( index<Is>{} );
                        }...
                          };
                          
                            return table[I](pf);
                            }    
                            
                            template<std::size_t N, class F>
                            auto magic_switch( std::size_t I, F&& f ) {
                              return magic_switch( I, std::forward<F>(f), std::make_index_sequence<N>{} );
                              }
                              

사용은 다음과 같습니다.

std::size_t r = magic_switch<100>( argc, [](auto I){
  return sizeof( char[I+1] ); // I is a compile-time size_t equal to argc
  });
  std::cout << r << "\n";
  

라이브 예 .

타입 enum을 컴파일 타임에 타입 맵에 등록 할 수 있다면 (타입 트레이 트 등을 통해), 매직 스위치를 통해 라운드 트립하여 런타임 enum 값을 컴파일 타임 타입 태그로 바꿀 수 있습니다.

template<class T> struct tag_t {using type=T;};

그런 다음 다음과 같이 직렬화 / 역 직렬화를 작성할 수 있습니다.

template<class T>
void serialize( serialize_target t, void const* pdata, tag_t<T> ) {
  serialize( t, static_cast<T const*>(pdata) );
  }
  template<class T>
  void deserialize( deserialize_source s, void* pdata, tag_t<T> ) {
    deserialize( s, static_cast<T*>(pdata) );
    }
    

가있는 경우 enum DataType특성을 작성합니다.

enum DataType {
  Integer,
    Real,
      VectorOfData,
        DataTypeCount, // last
        };
        
        template<DataType> struct enum_to_type {};
        
        template<DataType::Integer> struct enum_to_type:tag_t<int> {};
        // etc
        
        void serialize( serialize_target t, Any const& any ) {
          magic_switch<DataType::DataTypeCount>(
              any.type_index,
                  [&](auto type_index) {
                        serialize( t, any.pdata, enum_to_type<type_index>{} );
                            }
                              };
                              }
                              

모든 무거운 작업은 이제 enum_to_type특성 클래스 전문화, DataType열거 형 및 다음 형식의 오버로드에 의해 수행됩니다.

void serialize( serialize_target t, int const* pdata );

유형 안전합니다.

당신의 것을 참고 any실제로 아니다 any, 오히려 variant. 그것은 어떤 것도 아닌 제한된 유형의 목록을 포함합니다.

이것은 함수 magic_switch를 다시 구현하는 데 사용되며 .std::visitvariant

무엇이든 포함 하려면 지원할 작업을 결정하고에 저장할 때 실행되는 유형 삭제 코드를 작성 any하고 데이터와 함께 유형 삭제 된 작업을 저장해야합니다. 삼촌.



출처
https://stackoverflow.com/questions/39915986
댓글
공지사항
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31