You can disambiguate between the two declarations by inspecting the signature of the declared function. Here's a basic example of the templates required to inspect the parameter type. This could easily be generalized (or you could use Boost's function traits), but this is sufficient to demonstrate a solution for your specific problem:
#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 };
};
Here's an example that demonstrates the behavior:
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;
}
Once you can detect the qualification of the parameter type, you can write two wrapper functions that call iconv
: one that calls iconv
with a char const**
argument and one that calls iconv
with a char**
argument.
Because function template specialization should be avoided, we use a class template to do the specialization. Note that we also make each of the invokers a function template, to ensure that only the specialization we use is instantiated. If the compiler tries to generate code for the wrong specialization, you'll get errors.
We then wrap usage of these with a call_iconv
to make calling this as simple as calling iconv
directly. The following is a general pattern showing how this can be written:
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 */);
}
(This latter logic could be cleaned up and generalized; I've tried to make each piece of it explicit to hopefully make it clearer how it works.)