2014-02-07 3 views
0

C++ 문제가 있습니다. 템플릿 함수에 전달 된 형식 인수를 기반으로 형식을 생성하고 싶습니다.함수 호출을 기반으로 형식을 생성하는 C++ 메타 프로그래밍 문제/도전

설명해 드리겠습니다. 고려해야 할

X<int>(); 
    X<double>(); 

다른 예

A a; 

    a.M<int>(); 
    a.M<double>(); 

다음 a.Z() 실행 예

class A { 

    template<class B> M() { } 

    void Z() { 

    // NOTE: Here I want to call to X on each type that was feed it to M. 
    X<N1>(); 
    X<N1>(); 
    ... 
    X<NN>(); 

    } 

    template<class B> X() { } 
    }; 

... 독특한 유형 다음

A a; 

    a.M<int>(); 
    a.M<int>(); 
    a.M<double>(); 
    a.M<double>(); 

a.Z() 의지는 여전히 ... 실행 내가 M. 확인에 대한 호출에 따라 A 형을 생성하고

X<int>(); 
    X<double>(); 

주의! A 클래스는 템플릿 형식이 아니기 때문에 개념적으로 불가능하다고 생각합니다. 그런 식으로 변할 수는 없습니다. 사실 C++의 어떤 유형에서도 가능하지 않습니다 (제 생각에). 하지만 그 아이디어를 얻길 바랍니다.

메타 프로그래밍을 사용하여이 문제에 직면 할 수있는 방법을 기대하지만 조언이나 해결책 또는 참조를 환영합니다.

+0

왜 이렇게할까요? – ecatmur

+0

@ecatmur 우리는 어떤 종류의 객체를 생성 할 때 일반적인 프로그래밍과 최적화를 사용하고 있으며 매우 깨끗한 방법으로 리소스를 정리해야합니다. –

+1

컴파일 타임에'aZ()'를 확장하려면, 명령'aM ();'과'aM ();'는 실행시에는 연속적이지만 컴파일시에는 완전히 관련이 없습니다. 어때요? A a; a.Z(); 또는 A a; a.M () .Z();'? – aschepler

답변

4

메타 프로그래밍이 필요하지 않습니다.

class A { 
    using XPtr = void (A::*)(); 
    std::vector<XPtr> x_calls; 
    std::set<std::type_index> x_types; 

    template <typename B> void X() { ... } 

public: 
    template <typename B> void M() { 
    bool is_new = x_types.insert(std::type_index(typeid(B))).second; 
    if (is_new) 
     x_calls.push_back(&A::X<B>); 
    ... 
    } 

    void Z() { 
    for (auto&& ptr : x_calls) { 
     (this->*ptr)(); 
    } 
    } 
}; 
+0

그게 작동하지 않으면 예를 들어 M 을 두 번 호출하면 Z에서 2 개의 호출이 생성됩니다. 그 문제를 해결하기 위해 질문을 업데이트 할 것입니다. 하지만 고마워. –

+1

고유 한 유형으로 업데이트되었습니다. –

+0

이제 작동합니다. 감사. 그러나 솔직히 나는 생성 된 코드가 마음에 들지 않습니다. 나는 너의 것을 받아들이 기 전에 다른 옵션을 찾으려고 노력할 것이다. 그러나 다시, 고마워. –

1

당신은 boost::fusion::setboost::mpl를 사용하여 유사한 기능을 달성 할 수있다.

class A { 
    struct functoid { 
     template<typename T> 
     void operator(T t) 
     { 
      /* do something */ 
     } 
    } 
    template<class B> M() { 

     boost::mpl::for_each<B>(functoid()); 
    } 
} 

A a; 
a.template M<boost::fusion::set<int, double, ...>>(); 

는하지만,이 경우에, 당신은 실제 유형을 알고, 또는 operator() 일부 콜백을 등록해야합니다.

+0

세바스찬의 대답이 더 좋습니다. – nothrow

2

우선, 인터페이스가 실제로 MPL이 아닌 것 같습니다. MPL이 되려면 typedef MyType mpl::vector<int, double>과 같은 형식을 사용하고 각 유형에 대해 X<...>이라는 형식을 만드는 방법을 찾아야합니다. 그러나 ...

#include <iostream> 
#include <typeinfo> 
#include <vector> 
#include <functional> 
#include <algorithm> 

using namespace std; 

template< typename T> 
void X() { 
    cout<<typeid(T).name()<<endl; 
} 

struct A { 
    vector< function<void(void)> > callbacks; 
    void z() { 
    for(auto a : callbacks) a(); 
    } 

    template<typename T> 
    void M() { 
    callbacks.push_back([](){ X<T>();}); 
    } 
}; 

int main() { 
    A a; 
    a.M<int>(); 
    a.M<double>(); 
    a.z(); 
    return 0; 
} 

당신이 원하는 것을 않습니다.

$의 g ++ --std = C++
./a.out 11 & & 내가
D
SS

See it live