2014-02-18 3 views
3
나는 기능/템플릿과 매크로를 대체하려는

와 매크로를 대체합니다 함수/템플릿

#define FOO(f) \ 
    int result = m_Member.f; \ 
    switch (result) \ 
    { \ 
    case 1: \ 
     m_pMember1->f; \ 
     break; 
    case 2: 
     m_pMember2->f; \ 
     break; 
    } 

class foo 
{ 
public: 
    void foo1(int x, int y) 
    { 
     FOO(foo1(x, y)) 
    } 
    void foo2(int x, double y, void *z) 
    { 
     FOO(foo2(x, y)) 
    } 
protected: 
    fooA m_Member; 
    fooB m_Member1; 
    fooC m_Member2; 
}; 

그래서 내 문제는 함수 이름 인수와 함께 매크로에 전달된다. FOO (foo1, x, y)와 같은 호출을 다시 작성한 다음 가변 인수 목록을 처리 할 수 ​​있습니다. 그래서 매크로는 단지 하나의 함수 호출을 정의 할 것이다. 하지만 좀 더 우아한 해결책이있을 수 있습니다. 당신은 몇 가지 가상 기능 (여기 foo_base이라고 함) fooBfooC에 대한 기본 클래스를 추가 할 수 있습니다

+0

당신이 다형성을 고려겠습니까? 'fooB'와'fooC'는'foo1'과'foo2'를 선언하는 공통 조상을 공유 할 수 있습니까? –

답변

2

마찬가지로, 이것은 불가능합니다.

문제는 서식 파일이 기본적으로 형식에 안전하다는 것입니다. 그러나 귀하의 예는 그렇지 않습니다. 적용될 수있는 유형 세트를 제한하는 이름 인 foo2에는 고유 한 것이 없습니다!

은이 문제를 설명 일반적인 멤버 함수를 고려하려면

struct Foo { int doit(double x, double y); }; 

그것의 유형 int (Foo::*)(double,double)입니다.

메서드가 속한 클래스의 이름이 형식 자체에 표시되는 것에 유의하십시오.

따라서, 두 개의 관련없는 클래스에 doit를 호출 할 수 없습니다 ... 그래서 나는 당신이 어떤 반복거야 것을 두려워 : it works

class foo { 
public: 
    void foo1(int x, int y) 
    { 
     dispatch(&fooA::foo1, &fooB::foo1, &fooC::foo1, x, y); 
    } 

    void foo2(int x, double y, void *z) 
    { 
     dispatch(&fooA::foo2, &fooB::foo2, &fooC::foo2, x, y, z); 
    } 

private: 
    template <typename... Args> 
    void dispatch(int (fooA::* f)(Args...), 
        void (fooB::* g)(Args...), 
        void (fooC::*h)(Args...), 
        Args... args) 
    { 
     switch((m_Member.*f)(args...)) { 
     case 1: (m_Member1.*g)(args...); return; 
     case 2: (m_Member2.*h)(args...); return; 
     } 
    } 

    fooA m_Member; 
    fooB m_Member1; 
    fooC m_Member2; 
}; 

을합니다.

+0

좋아 보인다. 프로젝트의 툴 체인을 C++ 11로 바꿀 때까지 기다려야합니다. ( – user2018182

0

당신은 다음 코드를 사용하여이 작업을 수행 할 수 있습니다

class foo 
{ 
private: 
    template<typename... Ts> 
    void another_foo(int (fooA::*f)(Ts...), void (foo_base::*g)(Ts...), Ts const... vals) 
    { 
     switch ((m_Member.*f)(vals...)) { 
     case 1: 
      (m_pMember1->*g)(vals...); 
      break; 

     case 2: 
      (m_pMember2->*g)(vals...); 
      break; 
     } 
    } 

public: 
    void foo1(int x, int y) 
    { 
     another_foo(&fooA::foo1, &foo_base::foo1, x, y); 
    } 

    void foo2(int x, double y, void *z) 
    { 
     another_foo(&fooA::foo2, &foo_base::foo2, x, y); 
    } 

protected: 
    fooA m_Member; 
    fooB m_Member1; 
    fooC m_Member2; 
}; 

가상 기능을 가능성이 있기 때문에 devirtualised 얻을 것이다 고정 유형 m_pMember1m_pMember2은 정적으로 알려져 있습니다.

+0

'm_pMember1->''m_pMember1->'는'g_'을 호출해야한다고 생각합니다. 호출은'->'을 통해 이루어지기 때문에'm_pMember1'과'm_pMember2'의 동적 타입이 알려져 있지만 다소 괜찮습니다. 더 나쁜 짓을. –

+0

@MatthieuM. 고마워. 컴파일러가'another_foo' 호출을 인라인하면 아마 그것을 해결할 수 있습니다. – Simple

0

도움이 될 수 있습니다 다음과 같습니다 (http://ideone.com/5QIBZx)

#define Return(ret) decltype ret { return ret; } 

struct foo1Caller 
{ 
    template <typename T, typename... Args> 
    auto operator() (T& t, Args... args) -> Return((t.foo1(args...))) 
}; 

struct foo2Caller 
{ 
    template <typename T, typename... Args> 
    auto operator() (T& t, Args... args) -> Return((t.foo2(args...))) 
}; 


class foo 
{ 
public: 
    void foo1(int x, int y) 
    { 
     dispatch(foo1Caller(), x, y); 
    } 
    void foo2(int x, double y, void *z) 
    { 
     dispatch(foo2Caller(), x, y, z); 
    } 

private: 
    template <typename T, typename... Args> 
    void dispatch(T caller, Args... args) 
    { 
     switch (caller(m_Member, args...)) { 
      case 1: caller(m_Member1, args...); return; 
      case 2: caller(m_Member2, args...); return; 
     } 
    } 

    fooA m_Member; 
    fooB m_Member1; 
    fooC m_Member2; 
};