선언 된 함수의 시그니처를 검사하여 두 선언을 명확하게 할 수 있습니다. 다음은 매개 변수 유형을 검사하는 데 필요한 템플릿의 기본 예입니다. 이것은 쉽게 일반화 될 수 있지만 (또는 Boost의 기능 특성을 사용할 수 있음) 특정 문제에 대한 솔루션을 입증하기에 충분합니다.
#include <iostream>
#include <stddef.h>
#include <type_traits>
// I've declared this just so the example is portable:
struct iconv_t { };
// use_const<decltype(&iconv)>::value will be 'true' if the function is
// declared as taking a char const**, otherwise ::value will be false.
template <typename>
struct use_const;
template <>
struct use_const<size_t(*)(iconv_t, char**, size_t*, char**, size_t*)>
{
enum { value = false };
};
template <>
struct use_const<size_t(*)(iconv_t, char const**, size_t*, char**, size_t*)>
{
enum { value = true };
};
다음은 동작을 보여주는 예입니다.
size_t iconv(iconv_t, char**, size_t*, char**, size_t*);
size_t iconv_const(iconv_t, char const**, size_t*, char**, size_t*);
int main()
{
using std::cout;
using std::endl;
cout << "iconv: " << use_const<decltype(&iconv) >::value << endl;
cout << "iconv_const: " << use_const<decltype(&iconv_const)>::value << endl;
}
매개 변수 유형의 규정을 감지 할 수 있으면 호출하는 두 개의 래퍼 함수를 작성할 수 있습니다 iconv
. 하나 iconv
는 char const**
인수로 호출하고 다른 하나 iconv
는 char**
인수로 호출합니다 .
함수 템플릿 전문화는 피해야하므로 클래스 템플릿을 사용하여 전문화합니다. 또한 우리가 사용하는 전문화 만 인스턴스화되도록 각 호출자를 함수 템플릿으로 만듭니다. 컴파일러가 잘못된 전문화에 대한 코드를 생성하려고하면 오류가 발생합니다.
그런 다음 call_iconv
이를 iconv
직접 호출하는 것처럼 간단하게 호출하기 위해 사용을 래핑합니다 . 다음은 이것이 작성되는 방법을 보여주는 일반적인 패턴입니다.
template <bool UseConst>
struct iconv_invoker
{
template <typename T>
static size_t invoke(T const&, /* arguments */) { /* etc. */ }
};
template <>
struct iconv_invoker<true>
{
template <typename T>
static size_t invoke(T const&, /* arguments */) { /* etc. */ }
};
size_t call_iconv(/* arguments */)
{
return iconv_invoker<
use_const<decltype(&iconv)>::value
>::invoke(&iconv, /* arguments */);
}
(이 후자의 논리는 정리되고 일반화 될 수 있습니다. 나는 그것이 작동하는 방식을 더 명확하게하기 위해 각 부분을 명시 적으로 만들려고 노력했습니다.)