宣言された関数のシグネチャを調べることで、2 つの宣言を明確にすることができます。パラメータの型を検査するために必要なテンプレートの基本的な例を次に示します。これは簡単に一般化できます (または 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;
}
パラメーターの型の修飾を検出できたら、 を呼び出す 2 つのラッパー関数を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 */);
}
(この後者のロジックはクリーンアップして一般化することができます。うまくいけば、それがどのように機能するかを明確にするために、その各部分を明示的にしようとしました。)