Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C++ is it possible to disambiguate between an array ref and a pointer? [duplicate]

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.

like image 911
Omnifarious Avatar asked Apr 29 '19 21:04

Omnifarious


2 Answers

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);
    }
}
like image 90
Brian Bi Avatar answered Oct 09 '22 12:10

Brian Bi


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); }
like image 22
max66 Avatar answered Oct 09 '22 13:10

max66