Sie können zwischen den beiden Deklarationen unterscheiden, indem Sie die Signatur der deklarierten Funktion überprüfen. Hier ist ein grundlegendes Beispiel für die Vorlagen, die zum Überprüfen des Parametertyps erforderlich sind. Dies könnte leicht verallgemeinert werden (oder Sie könnten die Funktionsmerkmale von Boost verwenden), aber dies reicht aus, um eine Lösung für Ihr spezifisches Problem zu demonstrieren:
#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 };
};
Hier ist ein Beispiel, das das Verhalten demonstriert:
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;
}
Sobald Sie die Qualifikation des Parametertyps erkannt haben, können Sie zwei Wrapper-Funktionen schreiben, die aufrufen iconv
: eine, die iconv
mit einem char const**
Argument aufruft, und eine, die iconv
mit einem char**
Argument aufruft .
Da die Spezialisierung von Funktionsvorlagen vermieden werden sollte, verwenden wir eine Klassenvorlage, um die Spezialisierung durchzuführen. Beachten Sie, dass wir jeden Aufrufer auch zu einer Funktionsvorlage machen, um sicherzustellen, dass nur die von uns verwendete Spezialisierung instanziiert wird. Wenn der Compiler versucht, Code für die falsche Spezialisierung zu generieren, werden Fehler angezeigt.
Wir schließen diese dann mit einem ab call_iconv
, um das Aufrufen so einfach wie das iconv
direkte Aufrufen zu machen . Das Folgende ist ein allgemeines Muster, das zeigt, wie dies geschrieben werden kann:
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 */);
}
(Diese letztere Logik könnte bereinigt und verallgemeinert werden. Ich habe versucht, jedes Stück explizit zu machen, um hoffentlich klarer zu machen, wie es funktioniert.)