在C ++中是否可以消除数组引用和指针之间的歧义?

时间:2019-04-29 21:47:27

标签: c++ templates c++14 overloading

我有此代码:

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);
}

它可以工作,但是当删除#if 0周围的t1部分时,由于使用的模板模棱两可,它无法编译。有什么方法可以强制优先使用call_me的数组版本?

我尝试了许多不同的技巧来完成这项工作。我尝试将, int...添加到指针版本的模板参数列表中。我试过删除const。我都尝试过。我什至尝试将指针版本转换为C样式的varargs函数(也称为int call_me(T const *a, ...))。似乎没有任何作用。

我对一个答案很满意,该答案要求目前认为可以将其纳入C ++ 2a。

3 个答案:

答案 0 :(得分:7)

有一个简单的解决方法:

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);
    }
}

答案 1 :(得分:2)

如果您接受添加一个间接级别,则可以添加一个未使用的参数来赋予阵列版本优先级。

我的意思是

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); }

答案 2 :(得分:1)

我建议您使用 span 来达到相同的效果:

What is a "span" and when should I use one?

您只需将数组引用替换为固定大小的跨度即可:

#include <cstddef>
#include <gsl/span>

template <typename T, std::size_t size>
constexpr int call_me(gsl::span<T const, size> a)
{
    int total = 10;
    for (std::size_t i = 0; i < size; ++i) {
        total += a[i];
    }
    return total;
}

还有no ambiguity。更好的是,现在您可以在容器上使用标准库算法:

#include <numeric>

template <typename T, std::size_t size>
constexpr int call_me(gsl::span<T const, size> a)
{
    return std::accumulate(a.begin(), a.end(), 10);
}