I have this code:
template <typename T, ::std::size_t size>
using ary_t = T[size];
template <typename T, ::std::size_t size>
constexpr int call_me(ary_t<T const, size> &a)
{
int total = 10;
for (::std::size_t i = 0; i < size; ++i) {
total += a[i];
}
return total;
}
template <typename T>
constexpr int call_me(T const *a)
{
int total = 0;
for (int i = 0; a[i]; ++i) {
total += a[i];
}
return total;
}
#if 0
int t1()
{
return call_me("a test");
}
#endif
int t2()
{
char const * const s = "a test";
return call_me(s);
}
and it works, but when remove the #if 0
section around t1
it fails to compile because of an ambiguity in which template to use. Is there any way to force the array version of call_me
to be used preferentially?
I've tried a number of different tricks to make this work. I've tried adding , int...
to the template argument list for the pointer version. I've tried removing the const
. I've tried both. I've even tried making the pointer version into a C-style varargs function (aka int call_me(T const *a, ...)
). Nothing seems to work.
I'd be happy with an answer that requires what is currently believed will make it into C++2a.
There's an easy workaround:
template <typename T>
constexpr int call_me(T&& arg) {
if constexpr(std::is_pointer_v<std::remove_reference_t<T>>) {
return call_me_pointer(arg);
} else {
return call_me_array(arg);
}
}
If you accept to add a level of indirection, you can add an unused parameter to give the precedence to the array version.
I mean
template <typename T, std::size_t size>
constexpr int call_me_helper (ary_t<T, size> &a, int)
{
int total = 10;
for (std::size_t i = 0; i < size; ++i) {
total += a[i];
}
return total;
}
template <typename T>
constexpr int call_me_helper (T const * a, long)
{
int total = 0;
for (int i = 0; a[i]; ++i) {
total += a[i];
}
return total;
}
template <typename T>
constexpr int call_me (T const & a)
{ return call_me_helper(a, 0); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With