在 C++ 中,是否可以消除数组引用和指针之间的歧义?
In C++ is it possible to disambiguate between an array ref and a pointer?
我有这个代码:
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);
}
并且它有效,但是当删除 t1
周围的 #if 0
部分时,由于使用哪个模板不明确,它无法编译。有什么办法可以强制优先使用call_me
的数组版本?
我尝试了很多不同的技巧来完成这项工作。我尝试将 , int...
添加到指针版本的模板参数列表中。我试过删除 const
。我都试过了。我什至尝试将指针版本制作成 C 风格的可变参数函数(又名 int call_me(T const *a, ...)
)。似乎没有任何效果。
我很高兴得到一个答案,该答案需要目前认为会进入 C++2a 的内容。
有一个简单的解决方法:
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);
}
}
我建议你使用 span
:
达到同样的效果
您只需将数组引用替换为固定大小的跨度即可:
#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);
}
如果您接受添加一个间接级别,您可以添加一个未使用的参数以优先考虑数组版本。
我是说
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); }
我有这个代码:
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);
}
并且它有效,但是当删除 t1
周围的 #if 0
部分时,由于使用哪个模板不明确,它无法编译。有什么办法可以强制优先使用call_me
的数组版本?
我尝试了很多不同的技巧来完成这项工作。我尝试将 , int...
添加到指针版本的模板参数列表中。我试过删除 const
。我都试过了。我什至尝试将指针版本制作成 C 风格的可变参数函数(又名 int call_me(T const *a, ...)
)。似乎没有任何效果。
我很高兴得到一个答案,该答案需要目前认为会进入 C++2a 的内容。
有一个简单的解决方法:
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);
}
}
我建议你使用 span
:
您只需将数组引用替换为固定大小的跨度即可:
#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);
}
如果您接受添加一个间接级别,您可以添加一个未使用的参数以优先考虑数组版本。
我是说
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); }