1. ホーム
  2. c++

[解決済み] あるプラットフォームではchar**を受け取り、他のプラットフォームではconst char**を受け取るC++関数を、どのようにして移植的に呼び出すことができますか?

2023-03-27 03:22:55

質問

私の Linux (および OS X) マシンでは iconv() 関数はこのプロトタイプを持っています。

size_t iconv (iconv_t, char **inbuf...

であるのに対し、FreeBSDではこのようになります。

size_t iconv (iconv_t, const char **inbuf...

C++のコードを両方のプラットフォームでビルドしたいのですが、どうすればいいですか?C コンパイラでは char** に対して const char** パラメータを渡した場合(またはその逆の場合)、通常は単なる警告が表示されますが、C++では致命的なエラーとなります。ですから、もし私が char** を渡すと、BSDではコンパイルできません。 const char** を渡すと、Linux / OS X ではコンパイルできません。どうすれば、プラットフォームを検出しようとすることなく、両方でコンパイルするコードを書くことができるでしょうか?

私が持っていた 1 つの (失敗した) アイデアは、ヘッダーによって提供されるものをオーバーライドするローカル プロトタイプを提供することでした。

void myfunc(void) {
    size_t iconv (iconv_t, char **inbuf);
    iconv(foo, ptr);
}

これが失敗するのは iconv は C リンクを必要とし、また extern "C" を関数内に置くことはできません(なぜ?)

私が思いついた最もうまくいくアイデアは、関数ポインタそのものをキャストすることです。

typedef void (*func_t)(iconv_t, const char **);
((func_t)(iconv))(foo, ptr);

というような、他のもっと深刻なエラーを覆い隠してしまう可能性があります。

どのように解決するのですか?

もし、constの問題に目をつぶるだけなら、その区別を曖昧にする、つまり、char**とconst char**を相互運用可能にする変換を使えばよいのです。

template<class T>
class sloppy {}; 

// convert between T** and const T** 
template<class T>
class sloppy<T**>
{
    T** t;
    public: 
    sloppy(T** mt) : t(mt) {}
    sloppy(const T** mt) : t(const_cast<T**>(mt)) {}

    operator T** () const { return t; }
    operator const T** () const { return const_cast<const T**>(t); }
};

その後、プログラムの後半で

iconv(c, sloppy<char**>(&in) ,&inlen, &out,&outlen);

sloppy() は char** または const char* に変換し、それを char** または const char* のように、iconvの2番目のパラメータが要求するものであれば、何でもかまいません。

UPDATE: const_castを使用するように変更し、as castではなくsloppyを呼び出すようにしました。