2016-07-25 1 views
0

컴파일 타임에 키 -> 유형 맵을 생성 할 수 있으며, 각 키 - 값은 variadic의 인스턴스 함수가 호출됩니까?variadic 함수에 대한 호출로 채워지는 컴파일 타임 키 - 타입 맵 생성

template <typename T, typename ... Args> 
void writeToQueue(Args... args) { 
    //Do something with args. 
    // Insert to map. something akin to: 
    // CODEMAP[T] = Args... 
    // T -> Args... mapped when foo<T,Args...> is called. 
} 

또는 위에서

template <int code, typename ... Args> 
void writeToQueue(Args... args) { 
    //Do something with args. 
    // Insert to map. something akin to: 
    // CODEMAP[code] = Args... 
    // code -> Args... mapped when foo<code,Args...> is called. 
} 

는 요구 사항 매핑 대해 codemap이 다음 중 하나입니다 타입 -> 입력하거나 (가능한 중)하지만지도가 채워집니다 INT-> 입력 할 때 기능 foo가 호출되므로 코드와 args를 미리 아는 것은 필수 사항이 아닙니다.

이 모든 것이 가능합니까? boost/preprocessor/template 프로그래밍을 통해?

편집 : CODEMAP은 명시된 바와 같이 코드 -> 유형 정보를 저장하는지도입니다. 런타임 중에 리더 블록 (예 : R)은 foo()가 저장/처리 한 메시지를 읽고 메시지 시작 부분의 코드를 기반으로 구문 분석합니다. 코드는 항상 고정 크기 (4 문자 또는 1 int)입니다.

번역 단위가 같습니다.

편집 :

프로듀서 : 그래서 여기 거래의 FIFO 큐 (중요한 코드 핫 경로)에 데이터를 기록 -> 소비자 스레드가 읽기 및 대기열에서 정보를 처리합니다.

의사 코드는 다음과 같습니다 :

프로듀서 :

void Producer::run() { 
    // This guy shouldn't worry about the type of data being written. 
    // So, encapsulating data into structs and passing it to queue is 
    // out of question. 
    writeToQueue<Code1>(1,2,"123123",'a', 3.1416); 
    writeToQueue<Code2>(4,1,'b'); 

    template <int Code, typename ...Args> 
    void writeToQueue(Args... args) { 
    queue.insert(args...); 
    // Need code to args... mapping. So, decided to create static 
    // instantiation of a formatspecifier class. 
    static formatspecifier<Code, args...> f{}; 
    } 

    // To encode the type information to be used in run time. 
    template <int Code, typename ... Args> 
    class formatspecifier{ 
     formatspecifier() { 
      global::codemap[Code] = encodeTypeInfo<Args...>(); 
     } 
    }; 
} 

소비자 :

void Consumer::readfromQueue() { 
    while(true) { 
     if (queue.dataAvailable()) { 
     const auto code = queue.getCode(); 
     // get encoded type info format from global::codemap map. 
     const auto fmt = global::codemap[code]; 
     for (int i=0; i < fmt.len; i++) { 
      // I am unsure how this part should look. 
      process<fmt[0]::type>(queue.getData<fmt[0]::type>()); 
     } 
     } 
    } 
} 
+0

당신의 목표가 대해 codemap 무엇입니까? 사용 예를 제공하십시오. 또한 여러 번역 단위를 어떻게 다룰 것입니까? (전체 프로젝트에 대해 하나의 단일 코드 맵을 원하십니까? 아니면 각 TU에 대해 하나의 코드 맵이 충분한가요?) – Dutow

+0

그래서 멀티 맵을 사용하고 있으며'code' 키에 대해 임의의 수의 값을 한번에 삽입하고자합니다. 너가 원하는게 그거야? – Rerito

+0

"이전"CODEMAP이'foo'에 대한 모든 호출에 전달되고 새로운 CODEMAP이 반환되면 문제는 함수형 프로그래밍 언어로지도 데이터 구조를 구현하는 것으로 줄어 듭니다. 그러나 그것은 당신이 불변 값만을 가지고있는 프로그래밍 언어 (즉, TMP)로 가변 전역을 구현하려고하는 것처럼 보입니다 ... –

답변

0

따라서 다형성을 사용하여 시도했습니다.파생 된 형식의 메시지를 대기열에 저장하여 작동하는 것 같습니다. 대기열에서 제외하는 동안 vptr은 process()의 올바른 구현을 가리켜 야합니다.

class Message { 
    virtual void process() = 0; 
} 

template <typename... Args> 
class FormattedMessage : public Message { 
    std::tuple<Args...> data; 
    //Specialize process function for each formatted message. 
    void process() { 
     //As now I have the tuple, I can easily iterate/process it. 
    } 
} 

프로듀서 :

template <typename ...Args> 
void Producer::writeToQueue(Args... args) { 
    using fmttype = FormattedMessage<Args...>; 
    this->queue.push<fmttype>(args...); 
} 

소비자 :

void Consumer::readfromQueue() { 
    while(true) { 
     if (queue.dataAvailable()) { 
      this->queue.template front<Message>().process(); 
      this->queue.pop(this->queue.template front<Message>().size()); 
     } 
    } 
} 
+0

*'형식화 된 메시지'* -이 새로운 세부 사항이 질문에 더 잘 추가되어야합니다. 당신의 대답에서 나는'파생 된'클래스를 보지 못합니다, 당신은 무언가를 잊었습니까? – Wolf

+0

수정 됨. 'FormatteMessage'는 홀더 클래스 일 뿐이므로 argpack'Args ... '에 특유한 오버 라이딩 프로세스 함수는 유일한 정의를 가질 수 있습니다. 가상 포인터는'code'와'Args ... '를 매핑하는 문제를 해결합니다. 즉, unque 프로세스 함수 (특정 argpack'Args ...'를 처리합니다) – themagicalyang

1

가 대신지도를 가지고, 당신은 다음과 같은 code를 통해 구조체 템플릿 수 있습니다

enum Codes { 
    BEGIN_CODE = 0, 
    Code1, 
    Code2, 
    NB_CODES 
}; 

template <typename ... Args> 
struct param_pack { 
    // Alternatively you could also use std::tuple?! 
}; 

template <Code code> 
struct code_info; 

// You still have to manually define this at some point... 
// For all your different messages... 
template <> 
struct code_info<Code1> { 
    typedef param_pack<int, double, double> args_t; 
}; 

template <> 
struct code_info<Code2> { 
    typedef param_pack<int, float, float, long> args_t; 
} 

첫 번째 단계에서 우리는 다른 메시지 코드의 어딘가에 유형 정보를 확인했습니다. 그런 정보를 사용하여 어떻게 처리할까요?

namespace details { 
template <typename ArgPack> 
struct pack_processor; 

template <typename T, typename ... Args> 
struct pack_processor<param_pack<T, Args...>> { 
    static void process_pack(YourQueue& queue) { 
     process<T>(queue.getData<T>()); 
     pack_processor<param_pack<Args...>>::process_pack(queue); 
    } 
}; 

template <typename T> 
struct pack_processor<param_pack<T>> { 
    static void process_pack(YourQueue& queue) { 
     process<T>(queue.getData<T>()); 
    } 
}; 
} // namespace details 

template <Code code> 
process_message(YourQueue& queue) { 
    details::pack_processor<typename code_info<code>::args_t>::process_pack(queue); 
} 

그럼 당신은 우리가 "속임수"있어야하려면 ... 당신의 큐가 메시지의 코드에 따라에 적용 할 수있는 관련 처리 단계를 찾기 위해 다른 템플릿을 추가 할 수 있습니다 조금 : 그것은 몇 가지 템플릿 마법의 시간 : 런타임에는 원하는 코드 만 가질 수 있으므로 처리를 즉시 분기 할 수 없기 때문에 "템플릿 전환"트릭을 사용해야합니다. 이 아래에 설명되어

namespace details { 
// This is not static: 
// you can't have static polymorphism when you get information from runtime... 
template <Code ref_code> 
void process_data_with_code(Code code, YourQueue& queue) { 
    // We found the good code: 
    if (code == ref_code) { 
     // We retrieve the static information 
     // and run the appropriate process_pack specialization -> this is static 
     process_message<ref_code>(queue); 
    } else { 
     process_data_with_code<static_cast<Code>(ref_code-1)>(code, queue); 
    } 
} 

template <> 
void process_data_for_code<BEGIN_CODE>(Code code, YourQueue& queue) { 
    std::cout << "Code not found..." << std::endl; 
} 

} // namespace details 

void process_data(Code code, YourQueue& queue) { 
    process_data_for_code<static_cast<Code>(NB_CODE-1)>(code, queue); 
} 

당신은 더미 YourQueueprocess() 구현 Coliru에 실행 예를 찾을 수 있습니다.

이것은 소비자 부품을 해결합니다. pack_processor 전문화 내에 관련 방법을 추가하고 같은 종류의 템플릿 스위치 트릭을 사용하는 일반 writeToQueue 메소드를 추가하여 제작자 부품을 유사하게 해결할 수 있습니다.

+0

좋습니다. 내가 수동으로 다른 메시지를 정의하고 싶지 않았다는 것 외에는 대부분을 해결합니다. 나는 다형성을 사용하여 다른 접근 방식을 시도해 보았습니다. – themagicalyang

+0

글쎄, 정적 다형성 (IOW 템플릿 트릭)을 사용한다면 모든 것을 일정하고 생산자와 소비자가 이용할 수 있어야합니다. 이를 위해서는 메시지 유형을 수동으로 정의해야합니다. – Rerito

관련 문제