配列パラメーターの長さを推測するテンプレート関数があるとします。
template <size_t S>
void join(const char d[], const char *(&arr)[S]) { }
このように呼び出すと、すべてうまくいきます。
const char *messages[] = {
"OK",
"Not OK",
"File not found"
};
join("\n", messages);
しかし、次のように、空の配列で呼び出すと:
const char *messages[] = { };
join("\n", messages);
…コンパイルされません (clang 4.0 で):
targs.cpp:9:5: エラー: 'join' の呼び出しに一致する関数がありません join("\n", メッセージ); ^~~~ targs.cpp:4:6: 注: 候補テンプレートは無視されました: 置換失敗 [S = 0 で] void join(const char d[], const char *(&arr)[S]) { } ^ 1 エラーが発生しました。
C++ が長さ 0 の配列を好まないことに関係していると推測していますが、関数がテンプレートではなく、長さを別のパラメーターとして受け取る場合、メッセージを長さ 0 として宣言しても問題ありません。配列。
ここで何が起こっているのですか?良い回避策はありますか?
私の実際の使用例は、HTTP API エンドポイントが受け取るパラメーターを定義することであり、次のようになります。
const api_param_t params[] = {
{ API_TYPE_STRING, "foo" },
{ API_TYPE_UINT64, "bar" },
{ API_TYPE_STRING, "baz" }
}
const api_status_t status_codes[] = { … };
const api_middleware_t middleware[] = { … };
new api_endpoint("/foo", params, status_codes, middleware);
ほとんどのエンドポイントは少なくとも 1 つのパラメーターを取りますが、多くのエンドポイントは何も取りません。これは、実際、GCC と clang の両方が実装する拡張機能のようです (ただし、完全ではないように見えます)。いくつかの回避策を考えることができます:
api_endpoint
コンストラクターを特殊なケースの長さゼロの引数にオーバーロードします (ただし、長さゼロの各パラメーターをカバーするには、そのうちの 2 3が必要です)。これは、GCC/clang 拡張で問題ありません。配列の長さを推測しようとせず、別のパラメーターとして受け取ります (そして、長さ 0 の配列を引き続き使用します)。
これらのパラメータには、ベクトルのような高レベルのデータ構造を使用してください
魔法の値を使用して「空」を示す
…しかし、誰かがより良いアイデアを持っているなら、ぜひ聞いてみたい