您可以通过检查已声明函数的签名来消除两个声明之间的歧义。这是检查参数类型所需的模板的基本示例。可以很容易地将其概括(或者您可以使用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 */);
}
(可以对后一种逻辑进行清理和归纳;我试图将其每一部分都明确化,以期希望更清楚地说明其工作原理。)