Let’s say I have a template function that infers the length of an array parameter.
template <size_t S>
void join(const char d[], const char *(&arr)[S]) { }
If I call it like this, all is well:
const char *messages[] = {
"OK",
"Not OK",
"File not found"
};
join("\n", messages);
But if I call it with an empty array, like this:
const char *messages[] = { };
join("\n", messages);
…it doesn’t compile (with clang 4.0):
targs.cpp:9:5: error: no matching function for call to 'join' join("\n", messages); ^~~~ targs.cpp:4:6: note: candidate template ignored: substitution failure [with S = 0] void join(const char d[], const char *(&arr)[S]) { } ^ 1 error generated.
I’m guessing that it has something to do with C++ not liking zero-length arrays, but if the function is not a template and takes the length as a separate parameter, it doesn’t complain about me declaring messages as a zero-length array.
What’s up here, and is there a nice workaround?
My actual use case is defining the parameters an HTTP API endpoint takes and looks something like this:
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);
Most endpoints take at least one parameter but many take none. It looks like this is, indeed, an extension which both GCC and clang implement (but, looks like, not completely…). I can think of a few workarounds:
Overload the
api_endpoint
constructor to special case zero-length arguments (but I need 23 of them to cover each zero-length-able parameter), which the GCC/clang extension is OK with.Don’t try to infer the array length, take it as a separate parameter (and continue to use zero-length arrays)
Use a higher-level data structure like a vector for these parameters
Use a magic value to indicate "empty"
…but if anyone has better ideas I’d love to hear ‘em