문제

수동으로 번거 로움없이 템플릿 함수 포인터 세트를 설정할 수 있습니까? 다음은 내가 말하는 것을 설명하는 예입니다.

동적으로 전환 할 수있는 두 개의 구현 (Write0 및 Write1)이있는 "Writ 이 쓰기 기능은 인수 유형에 템플릿으로 표시됩니다. 이를 수행하는 한 가지 방법은 내부적으로 if 문을 사용하는 템플릿 프론트 엔드 기능 쓰기 ()를 갖는 것입니다.

이것은 내 필요에 따라 충분히 빠른 것으로 판명되었지만 이제는 기능 포인터 (재미를 위해)를 사용하여 똑같이 할 수 있는지 궁금해했습니다. 이 접근법의 문제점은 기능 포인터를 설정하는 것이 번거 로움이라는 것입니다. Write ()의 이상을 본질적으로 달성하는 다른 방법이 있지만 조건부가 없습니까 (직접 정적 파견)?

(기타 "규칙": MSG 클래스를 write () 메소드로 변경할 수 없으며 MSG를 MSG의 어댑터로 대체하기 위해 사이트 코드를 변경할 수 없습니다.)

fwiw, 나는 찾았다 이 기사 기본적으로 내가 여기서 말하는 것과 같은 말을합니다.

#include <iostream>
using namespace std;

template<typename T> void write0(T msg) { cout << "write0: " << msg.name() << endl; }
template<typename T> void write1(T msg) { cout << "write1: " << msg.name() << endl; }

// This isn't so bad, since it's just a conditional (which the processor will
// likely predict correctly most of the time).
bool use_write0;
template<typename T> void write(T msg) { if (use_write0) write0(msg); else write1(msg); }

struct MsgA { const char *name() { return "MsgA"; } };
struct MsgB { const char *name() { return "MsgB"; } };
struct MsgC { const char *name() { return "MsgC"; } };
struct MsgD { const char *name() { return "MsgD"; } };

// This doesn't work: templates may not be virtual.
#if 0
struct Writer { template<typename T> virtual void write(T msg) = 0; };
struct Writer0 { template<typename T> virtual void write(T msg) { cout << "write0: " << msg.name() << endl; } };
struct Writer1 { template<typename T> virtual void write(T msg) { cout << "write0: " << msg.name() << endl; } };
#endif

int main(int argc, char **argv) {
  use_write0 = argc == 1;

  // I can do this:
  write(MsgA());

  // Can I achieve the following without the verbosity (manual setup, named
  // template instantiations, etc.)?
  void (*pwriteA)(MsgA) = use_write0 ? (void(*)(MsgA)) write0<MsgA> : (void(*)(MsgA)) write1<MsgA>;
  void (*pwriteB)(MsgB) = use_write0 ? (void(*)(MsgB)) write0<MsgB> : (void(*)(MsgB)) write1<MsgB>;
  void (*pwriteC)(MsgC) = use_write0 ? (void(*)(MsgC)) write0<MsgC> : (void(*)(MsgC)) write1<MsgC>;
  void (*pwriteD)(MsgD) = use_write0 ? (void(*)(MsgD)) write0<MsgD> : (void(*)(MsgD)) write1<MsgD>;
  pwriteA(MsgA());
  pwriteB(MsgB());
  pwriteC(MsgC());
  pwriteD(MsgD());

  return 0;
}
도움이 되었습니까?

해결책

프로그램이 실행되는 동안 로깅 기능을 앞뒤로 전환하려면 각 유형의 기능 포인터를 수동으로 설정해야한다고 생각합니다.

스타트 업에서 로깅 함수를 선택하는 것으로 충분하다면 나중에 어떤 유형을 호출 할 것인지 알지 못하고 완전히 일반적인 방식으로 수행 할 수 있습니다.

// writer functions
template<typename T> void write0(T msg) { std::cout << 0; };
template<typename T> void write1(T msg) { std::cout << 1; };

// global flag
bool use_write0;

// function pointers for all types
template<typename T>
struct dispatch {
   typedef void (*write_t)(T);
   static write_t ptr;
};

// main write function
template<typename T>
inline void write(T msg) {
   (*dispatch<T>::ptr)(msg);
}

// the fun part
template<typename T>
void autoinit(T msg) {
   if (use_write0)
      dispatch<T>::ptr = &write0<T>;
   else
      dispatch<T>::ptr = &write1<T>;
   // call again for dispatch to correct function
   write(msg);
}

// initialization
template<typename T>
typename dispatch<T>::write_t dispatch<T>::ptr = &autoinit<T>;

// usage example
int main(int argc, char **argv) {
   use_write0 = (argc == 1);
   write("abc");
   return 0;
}

각 유형에 대해 T 첫 번째 전화 write<T>() 어떤 쓰기 기능을 사용해야하는지 결정합니다. 나중에 호출은 해당 함수에 대한 함수 포인터를 직접 사용합니다.

다른 팁

Don Clugston 's도 사용할 수도 있습니다 빠른 길거리 헤더. 런타임 오버 헤드를 생성하지 않고 진정으로 객체 지향 대표단을 생성하지 않습니다. 그것들을 사용하기위한 구문은 완벽하지는 않지만, 원시 기능 포인터와 함께 피는 것보다 조금 간단합니다.

기능 포인터 배열을 사용하지 않는 이유는 무엇입니까?

#include <iostream>
using namespace std;

template<typename T> void write0(T msg) { cout << "write0: " << msg.name() << endl; }
template<typename T> void write1(T msg) { cout << "write1: " << msg.name() << endl; }

template<typename T> struct WriteSelector
{
    static void(* const s_functions[])(T msg);
};
template<typename T> void(* const WriteSelector<T>::s_functions[])(T msg)=
{
    &write0<T>,
    &write1<T>
};

unsigned write_index=0;
template<typename T> void write(T msg)
{
    WriteSelector<T>::s_functions[write_index](msg);
}


struct MsgA { const char *name() { return "MsgA"; } };
struct MsgB { const char *name() { return "MsgB"; } };
struct MsgC { const char *name() { return "MsgC"; } };
struct MsgD { const char *name() { return "MsgD"; } };

void Test()
{
    write(MsgA());
    write(MsgB());
    write(MsgC());
    write(MsgD());
}

int main()
{
    Test();
    write_index=1;
    Test();
    return 0;
}

Write0/Write1 Choice와 MSGA/B/C .... Choice의 두 가지 축 변동이 있습니다.

개념적으로 그것은 당신이 a의 NXM 구현이 필요하다는 것을 의미합니다 write 기능. 물론, 쓰기 구현이 추가되거나 메시지 유형이 추가되면 이로 인해 RESP가됩니다. 추가 할 M 또는 N 추가 기능.

두 축 모두에 대해 정적 또는 동적 다형성을 사용하여 구현 여부를 선택할 수 있습니다. 정적 다형성은 템플릿을 사용하거나 기능 재정의를 사용하여 수행 할 수 있습니다.

각 클래스에서 M 쓰기 기능으로 n 요소 클래스 계층 구조를 작성하여 수행 할 수 있습니다. 그러나 곧 유지 보수 악몽이 될 것입니다. 메시지 내용이 런타임 다형성이 아닌 한. 그러나 문제는 메시지의 정적 다형성에 관한 것입니다.

런타임 다형성이 너무 정교 해져서 배제되므로 (그리고 템플릿 함수 가상을 가상 할 수 없으므로, 재정의의 진실성을 줄일 수 있습니다), 런타임 정보를 컴파일 타임 정보로 변환하여 약간의 유형-감소 루틴을 구현해야합니다. .

보다 구체적으로 : 주 행동을 템플릿으로 Tmain) 작가와 함께 사용하고 '실제'의 올바른 템플릿 인수로 호출합니다. main.

이것은 '글로벌'선택 변수의 사용을 생략하지만 객체 지향적이고 간결합니다.

    // twodimensionalpolymorph.cpp
    //

    #include <iostream>

    using namespace std;

    class Write0 {
        public: 
        template< typename tMsg > 
        void operator()( /*const*/ tMsg& msg ) { cout << "write0: " << msg.name() << endl; };
    };

    class Write1 {
        public: 
        template< typename tMsg > 
        void operator()( /*const*/ tMsg& msg ) { cout << "write1: "<< msg.name() << endl; };
    };

    struct MsgA { const char *name() { return "MsgA"; } };
    struct MsgB { const char *name() { return "MsgB"; } };
    struct MsgC { const char *name() { return "MsgC"; } };
    struct MsgD { const char *name() { return "MsgD"; } };

    // the Tmain does the real action
    //
    template< typename Writer >
    int Tmain( Writer& write, int argc, char** args ) {

        write( MsgA() );
        write( MsgB() );
        write( MsgB() );
        write( MsgD() );

        return 0;
    }

    // the main merely chooses the writer to use
    //
    int main( int argc, char** args ) {

        if( argc==1 )
            return Tmain( Write0(), argc, args);
        else
            return Tmain( Write1(), argc, args);

    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top