2012-05-03 13 views
3

나는 boost::variant을 사용할 수 있으며이 질문을하지 않아도된다는 것을 알고 있습니다. 그러나 boost::variant을 사용하면 많은 추악한 코드가 포함됩니다. 특히 방문객은 지저분합니다. 그래서, 더 이상 고민하지 않고 ...매개 변수없는 펑터와 C++에서 반환 값의 차별화 된 통합을 구현하는 방법은 무엇입니까?

나는 카레 기능의 게으른 평가를 구현하기 위해 다음과 같은 템플릿 클래스를 작성했습니다. (전체 조각에 대한 my previous question를 참조하십시오.)

template <typename> class curry; 

template <typename _Res> 
class curry< _Res() > 
{ 
    public: 
    typedef std::function< _Res() > _Fun; 
    typedef _Res _Ret; 

    private: 
    _Fun _fun; 

    public: 
    explicit curry (_Fun fun) 
    : _fun(fun) { } 

    operator _Ret() 
    { return _fun(); } 
}; 

그래서 내가 메모이 제이션을 포함하도록 업데이트 할. 개념적으로 매우 간단합니다.

private: 
    _Fun _fun; 

public: 
    explicit curry (_Fun fun) 
    : _fun(fun) { } 

으로 :

private: 
    bool _evaluated; // Already evaluated? 
    union 
    { 
     _Fun _fun; // No 
     _Res _res; // Yes 
    }; 

public: 
    explicit curry (_Fun fun) 
    : _evaluated(false), _fun(fun) { } 

    explicit curry (_Res res) 
    : _evaluated(true), _res(res) { } 

을하지만 왼쪽 두 가지가 있습니다 첫째, 나는 대체해야합니다. 첫째, 나는 operator _Ret을 업데이트해야합니다. 그렇게하면 게으른 평가를 수행하면 결과가 실제로 memoized됩니다. 둘째, _evaluated 값에 따라 _fun 또는 _res 중 하나가 삭제되도록 소멸자를 추가해야합니다. 그리고 여기에 어떻게 해야할지 잘 모르겠습니다.

먼저 _fun_res으로 바꾸는 올바른 방법입니까? 그렇지 않다면 어떻게해야합니까?

operator _Ret() 
{ 
    if (!_evaluated) { 
    _Fun fun = _fun; 

    // Critical two lines. 
    _fun.~_Fun(); 
    _res._Res(fun()); 

    _evaluated = true; 
    } 
    return _res; 
} 

둘째, 이것은 선택적 _fun_res 또는 파괴하는 올바른 방법? 그렇지 않다면 어떻게해야합니까?

~curry() 
{ 
    if (_evaluated) 
    _res.~_Res(); 
    else 
    _fun.~_Fun(); 
} 
+2

Yikes. 어딘가에는 추함이있을 것입니다. 날씨는 Visitor 패턴이나 다른 곳에 있습니다. –

+0

@ JohnDibling : C++에 적절한 자동 태그화된 유니온 타입이있는 경우 ... 그러나 패턴 매칭을 사용하면 완전히 유용하고 깨끗하게 사용할 수 있습니다. – pyon

+0

나는 당신이 여기서하려고하는 것을 완전히 이해하지 못하고있다. 무엇이든 포함 할 수 있지만 Visitor 패턴을 사용하지 않는 변형 유형을 다시 구현하려고합니까? –

답변

0

다른 주석 작성자가 명시한대로 공용체를 사용할 수 없지만 placement new을 사용할 수 있습니다. 이 A와 B 유형의 플랫폼에 정렬 제한 할 수 있으며, 그 제한을 적용하는 것은이 코드에 의해 처리되지 않도록

참고 :

여기에 새로운 배치를 사용하여 차별 노동 조합의 예입니다.

#include <iostream> 
#include <cstring> 

using namespace std; 

struct foo { 
    foo(char val) : c(val) { 
    cout<<"Constructed foo with c: "<<c<<endl; 
    } 

    ~foo() { 
    cout<<"Destructed foo with c: "<<c<<endl; 
    } 
    char c; 
}; 

struct bar { 
    bar(int val) : i(val) { 
    cout<<"Constructed bar with i: "<<i<<endl; 
    } 

    ~bar() { 
    cout<<"Destructed bar with i: "<<i<<endl; 
    } 

    int i; 
}; 

template < size_t val1, size_t val2 > 
struct static_sizet_max 
{ 
    static const size_t value 
    = (val1 > val2) ? val1 : val2 ; 
}; 

template <typename A, typename B> 
struct unionType { 
    unionType(const A &a) : isA(true) 
    { 
    new(bytes) A(a); 
    } 

    unionType(const B &b) : isA(false) 
    { 
    new(bytes) B(b); 
    } 

    ~unionType() 
    { 
    if(isA) 
     reinterpret_cast<A*>(bytes)->~A(); 
    else 
     reinterpret_cast<B*>(bytes)->~B(); 
    } 

    bool isA; 
    char bytes[static_sizet_max<sizeof(A), sizeof(B)>::value]; 
}; 

int main(int argc, char** argv) 
{ 
    typedef unionType<foo, bar> FooOrBar; 

    foo f('a'); 
    bar b(-1); 
    FooOrBar uf(f); 
    FooOrBar ub(b); 

    cout<<"Size of foo: "<<sizeof(foo)<<endl; 
    cout<<"Size of bar: "<<sizeof(bar)<<endl; 
    cout<<"Size of bool: "<<sizeof(bool)<<endl; 
    cout<<"Size of union: "<<sizeof(FooOrBar)<<endl; 
} 
+0

그래서 boost :: variant를 살펴보고 후드에서 비슷한 기술을 사용하지만 C++없이 정렬과 같은 모든 어려운 작업을 처리합니다. +11 특징, 두 가지 유형 이상, 등등. 당신은 정말로 boost :: variant를 boost :: get와 함께 사용해야 만합니다. – Soverman