2013-10-08 2 views
0

가정하자 나는 다음과 같은 정보가 일부 반사 메타 데이터를 가지고 : 함수 이름이 부여호출 C++ (회원) 함수를 동적으로

enum class type { t_int, t_double, t_str /* etc... */ }; 

struct meta_data 
{ 
    void* function; 
    void* instance; 
    std::vector<type> param_types; 
}; 

std::map<std::string, meta_data> ftable; 

내가이 맵에 함수를 호출하고 싶습니다를하고, 매개 변수를 모두 같은 문자열. 내 문제는 매개 변수를 변환하는 것이 아니라 (예 : boost::lexical_cast) 올바른 유형의 함수 포인터로 캐스팅하고 함수를 호출하는 것입니다. 가능한 8 가지 유형과 최대 8 개의 매개 변수를 허용하면 이미 내 코드에 많은 분기가 있습니다. 내가 피하고 싶지 않은 것 (의사 코드) :

 
    switch (md.param_types.size()) 
    { 
    case 0: 
     cast function pointer, call it 
     break; 
    case 1: 
     switch (md.param_types[0]) 
     { 
     case t_int: 
        int param = boost::lexical_cast(param_strings[0]); 
        cast function pointer, call with param 
     case ... 
     } 
     break; 
    case 2: 
     switch (md.param_types[0]) { 
     case t_int: 
      int param = boost::lexical_cast(param_strings[0]); 
      switch (md.param_types[1]) {...} // second param type.. 
     } 
     break; 
    case n... 
    } 

매개 변수와 가능한 유형 수가 매우 빠르게 폭발합니다. 내가 (의사 코드)의 라인을 따라 몇 가지 해결책을 찾고 있는데 :

for (auto& p : paramter_strings) 
{ 
    convert p to a variable of matching type (type id comes from meta_data). 
    store value 
} 

call function with stored values 

즉 함수 호출을위한 분기가 없다. 최소한의 상용구 코드로 (임의의 수의 매개 변수를 지원할 수 있음) 어떻게하면됩니까? 이것을 사용자 지정 스크립트 언어에 대한 바인딩을 만드는 것으로 생각할 수 있습니다.

+0

메모를 (등 오버 플로우, 제로 포인터) 오류를 처리하지 않는 것을 알고있다. 또한 호출 규칙이 광범위하고 전달 된 매개 변수의 유형에 따라 달라 지므로 스택 개념은 일반적으로 작동하지 않습니다. 제 마음에 오는 유일한 것은 재귀적인 템플릿 호출이 하나씩 매개 변수를 추가 한 다음 마침내 "진짜"라고 부르는 것입니다. 그러나 전체적인 아이디어는 매우 미친 짓이다 ... – PlasmaHH

+0

이 질문에'lua'라고 태그를 붙였다. Lua 스택인가 아키텍처 스택인가? 또한, 멤버 함수를 호출하는 경우'function'은 적어도'void (dummy :: * function)()'유형을 가져야하고 올바른 함수 유형을'reinterpret_cast '할 수 있습니다. – Simple

+0

@Simple, 아니 루아 태그는 실수 였어. 내가 삭제했지만 재 태그를 잊어 버린이 PC에 관한 초안 질문이 있었다. 결정된. –

답변

0

나는 하나의 접근법을 생각해 냈습니다.

부호없는 int V의 벡터가 있다고 가정하고 벡터의 모든 요소가 음수가 아닌 이고 N (또는 20)보다 작은 것으로 알고 있다고 가정 해 보겠습니다. 여기 당신이 양의 정수에 벡터 V를 변경하려면 전화를 할 것입니다 : 여기

n = sequence_to_code(V,N); // or n = encode(V,20U); 

코드입니다.

long sequence_to_long(const std::vector<unsigned int> & L, 
         unsigned long n) { 
    long result = 0L; 
    std::vector<unsigned int>::const_iterator w=L.begin(),e=L.end(); 
    if(w!=e) { 
    result += (*w)+1; 
    unsigned long the_pow = n; 
    unsigned int i = 1U; 
    ++w; 
    while(w!=e) { 
     result += (*w+1)*(the_pow); 
     ++w;++i;the_pow *= n; 
    } 
    } 
    return result; 
} 

실제로 "unsigned long"이 반환되었을 것입니다.

또한이 동일한 루틴을 텍스트 파일을 만드는 프로그램과 함께 사용할 수 있습니다. 이 텍스트 파일에는 C++ 코드가 들어 있습니다. "the_defines.hpp"를 생성했다고 가정합니다. 예를 들어 설명하겠습니다 ...

예를 들어, t_int = 0; t_double = 1, d_str = 2 이며 세 가지 유형 만 있습니다. 그런 다음 "the_define.hpp는"파일 수 :

다음이 코드는 다음 방법으로 사용될 수
#define TYPE_EMPTY 0U 
#define TYPE_INT 1U 
#define TYPE_DOUBLE 2U 
#define TYPE_STR 3U 
#define TYPE_INT_INT 4U 
#define TYPE_DOUBLE_INT 5U 

:

물론
std::vector<unsigned int> L; 
// add entries to L 
long n = sequence_to_long(L,3UL); 
switch(n) { 
    case TYPE_INT: 
    std::cout << "an integer\n"; 
    break; 
    case TYPE_INT_DOUBLE: 
    std::cout << "two args; first is an int; second is a double\n: 
    break; 
} 

, 당신은을 가진 텍스트 파일을 만들 수 있습니다 아주 긴 열거 형 (#define을 피하기 위해 신경 쓰는 경우)을위한 코드. 예를 들어,

enum class extended_type { 
    type_int, 
    type_double, 
    type_str, 
    type_int_int, 
    type double_int, 

등입니다.

(하나 이상의) 텍스트 파일을 만드는 프로그램을 작성할 수도 있습니다. 이러한 텍스트 파일도 C++ 코드로 작성됩니다.예를 들어, 생성 된 파일 가 될 수있다 : 나는 또한 인라인 함수 또는 일반 기능을 사용하여 주조하는 것이 좋습니다 것

case t_str_str: 
    FILLIN; 
    break; 
} 

때까지 등등

swtich(n) { 
    case empty: 
    FILLIN 
    break; 
    case t_int: 
    FILLIN 
    break; 

하고 있습니다. 예를 들어,

inline int inside_int(foo f) { 
    const bar & b = * reinterpret_cast<const bar *>(f.pointer()); 
    return b.d_x; 
} 

나는이 건조하기 때문에 (자신을 반복하지 않는 것) 함수의 모든 인스턴스를 검색 할 수있는 것이 좋습니다.

나는이 프로그램이 대부분의 구현에 * 무효보다 큰 특정 함수 포인터 유형이 있다는 것을

마크