2011-08-16 8 views
0

내가 가진 가정함수가 인수 목록의 순열을 수락하는 표준 방법은 무엇입니까?

class A,B,C; 

const A a_def; 
const B b_def; 
const C c_def; 

void f(A a=a_def, B b=b_def, C c=c_def); 

이 내가 기본 매개 변수를 사용하려면, 나만 그냥 c, 또는 bc 또는 이들의 세 가지를 모두 생략하거나 할 수 있다면,하지 -하지만 단지 a 또는 b 혼자. 그러나 인수 유형을 혼합 할 수 없으므로 f(A(), C()) (사실 f(B(), C(), A()) : 인수의 순서는 임의이며 실제로는 의미가 없습니다)를 호출하는 것은 완전히 불가능합니다.

이 함수를 호출이 다른 방법을 사용하려면, 지금은 단지 세 개의 매개 변수 (3! = 6 순열)에 대한 허용하지만 사에서 지루한 얻을 수있는 모든 순열 수동

void f(A a, C c,  B b=b_def) { f(a,b,c); } 
void f(B b, A a=a_def, C c=c_def) { f(a,b,c); } 
void f(B b, C c,  A a=a_def) { f(a,b,c); } 
void f(C c, A a=a_def, B b=b_def) { f(a,b,c); } 
void f(C c, B b,  A a=a_def) { f(a,b,c); } 

(4 과부하하는 경향이 ! = 24 순열) 및 5 개 매개 변수 (5! = 120 순열)의 범위를 벗어났습니다.

가변 인수 목록이나 어떤 종류의 템플릿 메타 프로그래밍을 통해 모든 오버로드를 실제로 수행하지 않고도이 기능을 자동으로 수행 할 수있는 방법이 있습니까?

+2

왜이 작업을 수행 하시겠습니까? 그것은 나쁜 생각처럼 보입니다. 그러나 명명 된 인수를 허용하는 Boost.Parameters 라이브러리 (http://www.boost.org/doc/libs/1_37_0/libs/parameter/doc/html/index.html)가 있습니다. –

+0

혜택이 보이지 않습니다. 사용자가'f (a_def, some_b, some_c); '라고 타이프하는 것이 잘못된 이유는 무엇입니까? – GManNickG

+0

@Travis "왜 이것을하고 싶습니까?"주로 하나의 단일 인수 (항상 같은 것은 아님)에 기본 매개 변수를 사용하고 싶지만, 어떤 순서로든 특정 함수 호출에서 가장 명확하게 보일 것입니다. – leftaroundabout

답변

2

매개 변수를 전달할 구조체를 만듭니다.

class Params{ 
public: 
    Params();// set defaults 
    Params& A(int); 
    Params& B(int); 
    int a,b; 
}; 

다음 C++ 0X 및 부스트 조금 (쉽게 대체 할 수있는 후자) 혼합

f(Params().A(5)); 
+0

그게 실제로 해결책이지만 컴파일 타임에 완전히 작동하고 사용자가 일반적인 인수 목록 방식으로 함수를 호출 할 수있는 방법을 선호합니다. – leftaroundabout

+0

궁금합니다. 다른 fn과 함께 : - int call() {return f (a, b);} Params(). A (5) .call(); 완전히 인라인 되었습니까? – QuentinUK

+0

@QuentinUK : 물건 더미에 따라 다르지만 예, 단순한 경우 인라인됩니다. – Dani

0

전화 :

typedef boost::variant<A, B, C> Arg; 
void f(std::initializer_list<Arg> args) 
{ 
    A *a = NULL; 
    B *b = NULL; 
    C *c = NULL; 

    // for each arg, assign to a, b, or c, 
    // possibly throwing if one type is used multiple times 

    if (!a) 
     a = new A(); 
    // and similar for B and C, or use smarter pointer types 

    f(*a, *b, *c); 
} 

과 같이 호출을하는 그것보다 약간 더 추악합니다 :

f({C(), B()}); 

이 테스트를하지는 않았지만 작동 할 수 있다고 생각합니다.

1

IMHO 일반적으로 가장 좋은 해결책은 매개 변수를 전달하는 구조를 정의하는 것입니다.

그러나 당신은 원하지 않는다고 말하면 정상적인 사용법 표기법을 원합니다.

그런 경우 부스트 매개 변수 라이브러리가 가장 간단합니다.

부스트를 사용할 수없는 경우 직접 할 수 있습니다.

그러나 DIY "부스트 매개 변수"와 같은 해법의 코드 양은 인수의 수가 2 차이지만 계승보다 훨씬 뛰어나지 만 여전히 일종의 금지적이고 & hellip입니다. 아래 코드 예제를 제공합니다. 주요 아이디어는 유형별로 인수를 식별 한 다음 컴파일 타임에 쉽게 정렬 할 수 있습니다.

template< class Type > 
struct Pointer 
{ 
    Type const* p_; 
    Pointer(Type* p = 0): p_(p) {} 
}; 

template< class Type, class Args > 
Type const* pointer(Args const& args) 
{ 
    return static_cast< Pointer<Type> const& >(args).p_; 
} 

template< class Type, class Args > 
Type const*& pointerRef(Args& args) 
{ 
    return static_cast< Pointer<Type>& >(args).p_; 
} 


//----------------------------------------------------- 

class A {}; class B {}; class C {}; 
A const a_def; B const b_def; C const c_def; 

void foo(A const* pa, B const* pb, C const* pc) 
{ 
    A const& a = (pa? *pa : a_def); 
    B const& b = (pb? *pb : b_def); 
    C const& c = (pc? *pc : c_def); 

    // Whatever, use a b c here. 
} 

struct FooArgs 
    : Pointer<A> 
    , Pointer<B> 
    , Pointer<C> 
{}; 

void foo(FooArgs const& args) 
{ 
    foo(pointer<A>(args), pointer<B>(args), pointer<C>(args)); 
} 

void foo() 
{ 
    foo(FooArgs()); 
} 

template< class T1 > 
void foo(T1 const& v1) 
{ 
    FooArgs  args; 

    pointerRef<T1>(args) = &v1; 
    foo(args); 
} 

template< class T1, class T2 > 
void foo(T1 const& v1, T2 const& v2) 
{ 
    FooArgs  args; 
    pointerRef<T1>(args) = &v1; 
    pointerRef<T2>(args) = &v2; 
    foo(args); 
} 

template< class T1, class T2, class T3 > 
void foo(T1 const& v1, T2 const& v2, T3 const& v3) 
{ 
    FooArgs  args; 
    pointerRef<T1>(args) = &v1; 
    pointerRef<T2>(args) = &v2; 
    pointerRef<T3>(args) = &v3; 
    foo(args); 
} 

int main() 
{ 
    foo(B()); 
} 

언급 한 것처럼 DIY가 내 마지막 선택입니다.

이 예제 코드에서 오류 검사가 생략되었습니다. 예를 들어, 두 개 이상의 실제 인수가 같은 유형 인 경우 코드를 컴파일해서는 안됩니다. 나는 또한 형식적 논증이 모두 같은 유형이 아닌 경우까지 일반화를 생략했다. 이러한 생략 된 것은 더 복잡한 것에 기여합니다. 따라서 위의 내용이 금지 된 것처럼 보이는 경우, "풀 버전"에서와 같이 어떤 내용인지 생각하십시오.

엄격한 형식의 선택적 인수가 필요한 경우를 예로 들면 다음과 같습니다. 클래스 계층 구조의 생성자는 내 블로그 게시 "How to do typed optional arguments in C++98"을 참조하십시오.

건배 &th,