2011-11-22 6 views
2

우리는 우리의 코드를 리팩터링하려고하고 있으며 다음과 같은 개선 사항 중 하나가 있습니다. 많은 함수가 많은 인수를 갖지만 많은 함수가 공통 하위 집합을 공유합니다. 그래서 우리는 그것들을 그룹 짓는 구조를 만들고 싶습니다. 문제는 일부 함수는 const가 아닌 일부 매개 변수가 필요하다는 것입니다. 이러한 함수 중 일부는이 매개 변수 그룹화 구조를 제공하는 이러한 함수의 하위 집합을 호출 할 수 있어야하지만 다음 제한이 있습니다. 호출 된 함수는이 구조체의 constness를 "저하"시킬 수 없습니다 (다음 예제 참조). 이 구조체의 모든 필요한 변형을 구현하면 문제는 해결되지만 우아하게는 해결되지 않습니다. 우리가 작업중인 하나의 해결책은 예컨대, 템플릿을 사용하는 것입니다함수 인수 그룹화 및 const

template<class A, class B, class C> 
struct my_container 
{ 
    A a; 
    B b; 
    C c; 
}; 

void foo1(my_container<int, char, float const> & my_cont) 
{ 
} 

void foo2(my_container<int const, char, float const> & my_cont) 
{ 
    // This should NOT be allowed: we do mind something being const to be treated by the 
    // called function as non-const. 
    foo1(my_cont); 
} 

void foo3(my_container<int, char, float> & my_cont) 
{ 
    // This should be allowed: we don't mind something being non-const to be treated by the 
    // called function as const. 
    foo2(my_cont); 
} 

우리의 문제는에서는 foo2 컴파일러가 불평없이 foo1은 호출이며, 우리는 정반대을하고 싶습니다. 템플릿으로 구현할 수 있습니까? 다른 기술이 있습니까?

+0

const가 개별적으로 달라지는 경우 나에게 보입니다. 그 주장을 그룹화하려고하지 마십시오. – visitor

+0

템플릿은 관련성이없는 세 개의 값을 함께 뭉치 게한다는 것을 나타냅니다. - 관련 기능에 대한 실제 수업이있는 경우 일반적으로 부분 수정이 가능하다고 생각하지 않습니다. 예를 들어 Point 인스턴스의 x 좌표 만 수정하고 y는 수정하지 않는 함수는 허용되지 않습니다. 그것이 중요하다면, 당신은 그것들을 별도의 주장으로 전달할 것입니다. – UncleBens

답변

0

약간의 메타 프로그래밍으로 해결책을 찾았습니다. 꽤 추한하지 throughoutly 테스트하지만, 어쨌든 보이는 : 모든 정의되지 않은 동작에 경계없이 "상자 밖으로"일반적으로

#include <iostream> 
#include <boost/type_traits.hpp> 

template<class A, class B, class C> 
struct my_container 
{ 
    A a; 
    B b; 
    C c; 

    template<typename An, typename Bn, typename Cn> 
    operator my_container<An,Bn,Cn>&() 
    { 
     /* First, check whether compatible at all */ 
     BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<A>::type, typename boost::remove_cv<An>::type>::value)); 
     BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<B>::type, typename boost::remove_cv<Bn>::type>::value)); 
     BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<C>::type, typename boost::remove_cv<Cn>::type>::value)); 
     /* Enforce const'ness */ 
     BOOST_STATIC_ASSERT(!boost::is_const<A>::value || boost::is_const<An>::value); 
     BOOST_STATIC_ASSERT(!boost::is_const<B>::value || boost::is_const<Bn>::value); 
     BOOST_STATIC_ASSERT(!boost::is_const<C>::value || boost::is_const<Cn>::value); 

     return *reinterpret_cast< my_container<An,Bn,Cn>* >(this); 
    } 
}; 

void foo1(my_container<int, char, float const> & my_cont) 
{ 
} 

void foo2(my_container<int const, char, float const> & my_cont) 
{ 
    // This should NOT be allowed: we do mind something being const to be treated by the 
    // called function as non-const. 
    //foo1(my_cont); /// BOOST_STATIC_ASSERT fails! Hurray! 
} 

void foo3(my_container<int, char, float> & my_cont) 
{ 
    // This should be allowed: we don't mind something being non-const to be treated by the 
    // called function as const. 
    foo2(my_cont); /// No complaints! Hurray! 
} 

int main(int argc, char* argv[]) 
{ 
    my_container<int,char,float> foobar; 

    foo3(foobar); 

    return 0; 
} 
1

어느 쪽도 작동하지 않아야합니다. 템플릿의 다른 인스턴스화는 암시 적 변환없이 미발행 유형입니다. 따라서 my_container<int, char, float const>, my_container<int const, char, float const>my_container<int, char, float>은 모두 암묵적인 변환없이 유형과 관련이 없습니다.

당신이 상속을 결정하는 메타 프로그래밍 트릭을 사용하여 상속을 사용하여 뭔가를 작동 할 수 있어야한다,하지만 난 방법을 잘 해요, 나는 그것보다 가치가 더 많은 노력이 될 것이라고 생각한다.

+0

네 말이 맞지만 그럼에도 불구하고 나는 그것을 빨리 테스트했다. 예상 한대로 g ++ 4.4에서는 둘 다 작동하지 않습니다. 또는 MSVC 2010. – zerm

1

작동합니다 이 방법이 간접의 또 다른 수준으로 달성 될 수있다. 원본 멤버를 참조하는 뷰 클래스를 추가하십시오. Constence는 암시 적으로 추가 할 수는 있지만 삭제할 수는 없습니다.

template<class A, class B, class C> 
struct my_container 
{ 
    A a; 
    B b; 
    C c; 
}; 

template <class A, class B, class C> 
class my_container_view 
{ 
    A* a_; 
    B* b_; 
    C* c_; 

public: 
    template <class A_, class B_, class C_> 
    my_container_view(my_container<A_, B_, C_>& source): 
     a_(&source.a), b_(&source.b), c_(&source.c) 
    {} 
    template <class A_, class B_, class C_> 
    my_container_view(my_container_view<A_, B_, C_>& source): 
     a_(&source.a()), b_(&source.b()), c_(&source.c()) 
    {} 
    A& a() const { return *a_; } 
    B& b() const { return *b_; } 
    C& c() const { return *c_; } 
}; 

void foo1(my_container_view<int, char, float const> my_cont) 
{ 
    my_cont.a() = 10; 
    my_cont.b() = 'a'; 
    my_cont.c() /*= 3.14*/; 
} 

void foo2(my_container_view<int const, char, float const> my_cont) 
{ 
    my_cont.a() /*= 10*/; 
    my_cont.b() = 'a'; 
    my_cont.c() /*= 3.14*/; 

    //foo1(my_cont); //not allowed 
} 

void foo3(my_container_view<int, char, float> my_cont) 
{ 
    my_cont.a() = 10; 
    my_cont.b() = 'a'; 
    my_cont.c() = 3.14; 
t 
    foo2(my_cont); 
} 

int main() 
{ 
    my_container<int, char, float> mc; 
    foo1(mc); 
    foo2(mc); 
    foo3(mc); 
} 

(그래도이 가치가 얼마 일반적으로 클래스와, 내 의심을 가지고, 하나는 모든 회원을 수정할 수 있습니다 -. 당신은 당신이하지 않으려는 사람을 수정하지 마십시오 - 이 수준의 제어를 원할 경우, 각 인수를 별도로 전달해야합니다. 즉, 수행중인 것과 반대입니다.

+0

부스트가 필요하지 않은 것 외에 내 솔루션에 비해 어떤 이점이 있는지 배우고 싶습니다. 당신의 발언에 관해서, OP는 그의 질문의 처음 두 문장에서 그의 유스 케이스를 명확하게 만들었다 고 생각합니다. – zerm

+0

@ zerm : 기술적으로 관련이없는 유형 간의 reinterpret_casting이 기술적으로 정의되지 않은 동작이라고 의심 스럽지만 실제로 작동하지 않는 이유는 알 수 없습니다. - 의심스러운 점은 "문제는 일부 기능에는 const 매개 변수 중 일부 매개 변수가 필요하고 일부 매개 변수는 필요하지 않다는 것입니다." - 결과 객체가 실제로 전체를 형성한다면 나는 그런 딜레마를 만난 적이 없다. 또는 더 세분화 된 제어를 원한다면 각 구성원을 개별적으로 전달하십시오. 각 구성원마다 고유 한 constence를 가질 수 있습니다. – UncleBens

+0

reinterpret_cast의 좋은 점은 두 가지 유형이 모두 같아야한다는 것 (const'ness 옆)과 컨버터블 만 필요하지 않기 때문에 해결책을 고쳤습니다. reinterpret_cast가 문제를 일으키는 이유는 없습니다. 나는 std가 말하는 것을 검사 할 것이다. – zerm