您可以通过检查声明函数的签名来消除两个声明之间的歧义。这是检查参数类型所需的模板的基本示例。这可以很容易地概括(或者您可以使用 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**
参数调用。
因为应该避免函数模板特化,所以我们使用类模板来进行特化。请注意,我们还将每个调用程序都设为函数模板,以确保仅实例化我们使用的特化。如果编译器试图为错误的特化生成代码,你会得到错误。
然后我们用 a 包装它们的用法,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 */);
}
(后一种逻辑可以被清理和概括;我试图让每一部分都明确,希望能更清楚地说明它是如何工作的。)