c++ - 是否可以重载可以从指针告诉固定数组的函数?

标签 c++ arrays pointers c++11

动机:

几乎是为了好玩,我正在尝试编写一个函数重载,它可以区分参数是固定大小的数组还是指针。

double const  d[] = {1.,2.,3.};
double a;
double const* p = &a;
f(d); // call array version
f(p); // call pointer version

我发现这特别困难,因为众所周知的事实是数组迟早会衰减为指针。一个天真的方法是写

void f(double const* c){...}
template<size_t N> void f(double const(&a)[N]){...}

不幸的是,这不起作用。因为在最好的情况下,编译器会确定数组调用 f(d)以上是模棱两可的。

部分解决方案:

我尝试了很多东西,我能得到的最接近的是以下具体代码。另请注意,在此示例代码中,我使用 char而不是 double ,但最后很相似。

首先,我必须使用 SFINAE 在函数的指针版本中禁用转换(从数组 ref 到 ptr)。其次,我必须重载所有可能的数组大小(手动)。

[可编译代码]

#include<type_traits> // for enable_if (use boost enable_if in C++98)
#include<iostream>
template<class Char, typename = typename std::enable_if<std::is_same<Char, char>::value>::type>
void f(Char const* dptr){std::cout << "ptr" << std::endl;} // preferred it seems

void f(char const (&darr)[0] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[1] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[2] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[3] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[4] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[5] ){std::cout << "const arr" << std::endl;}
void f(char const (&darr)[6] ){std::cout << "const arr" << std::endl;} // this is the one called in this particular example
// ad infinitum ...

int main(){     
    f("hello"); // print ptr, ok because this is the fixed size array
    f(std::string("hello").c_str()); // print arr, ok because `c_str()` is a pointer
}

这可行,但问题是我必须为 N 的所有可能值重复该函数并使用 template<size_t N>让我回到零平方,因为使用模板参数,两个调用回到了平等的地位。 换句话说,template<size_t N> void f(char const(&a)[N]){std::cout << "const arr" << std::endl;}没用。

有什么方法可以概括第二个重载而不回退到模棱两可的调用?还是有其他方法?

也欢迎提供 C++ 或 C++1XYZ 答案。

两个细节:1)我使用了clang对于上述实验,2) 实际 f最终将成为 operator<< ,我想知道这对解决方案是否重要。


解决方案总结(基于其他人的以下)并适应具体类型char的例子。两者似乎都依赖于制作 char const*编译器的指针不太明显:

  1. 一个奇怪的(便携?),(来自@dyp的评论。)在指针版本中添加引用限定符:
    template<class Char, typename = typename std::enable_if<std::is_same<Char, char>::value>::type>
    void f(Char const* const& dptr){std::cout << "ptr" << std::endl;}
    
    template<size_t N>
    void f(char const (&darr)[N] ){std::cout << "const arr" << std::endl;}
  1. 一个优雅的(来自@user657267 的特殊情况)
    template<class CharConstPtr, typename = typename std::enable_if<std::is_same<CharConstPtr, char const*>::value>::type>
    void f(CharConstPtr dptr){std::cout << "ptr" << std::endl;}
    
    template<size_t N>
    void f(char const (&darr)[N] ){std::cout << "const arr" << std::endl;}

最佳答案

这似乎对我有用

#include <iostream>

template<typename T>
std::enable_if_t<std::is_pointer<T>::value>
foo(T) { std::cout << "pointer\n"; }

template<typename T, std::size_t sz>
void foo(T(&)[sz]) { std::cout << "array\n"; }

int main()
{
  char const* c;
  foo(c);
  foo("hello");
}

奖励std::experimental::type_traits:

using std::experimental::is_pointer_v;
std::enable_if_t<is_pointer_v<T>>

你的评论让我尝试了一些更简单的方法

template<typename T> void foo(T) { std::cout << "pointer\n"; }
template<typename T, unsigned sz> void foo(T(&)[sz]) { std::cout << "array\n"; }

当然,这里的问题是 foo 现在可以为任何类型调用,这取决于您希望参数检查的松懈程度。


另一种方法是(ab)使用右值引用

void foo(char const*&) { std::cout << "pointer\n"; }
void foo(char const*&&) { std::cout << "array\n"; }

显然这不是万无一失的。

关于c++ - 是否可以重载可以从指针告诉固定数组的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28182838/

相关文章:

c++ - std::dynamic_pointer_cast 成功调用非初始化类

c++ - 如何使用 libpqxx API 同时插入数据? (PostgreSQL,线程)

c++ - boost asio io_service 是否保证两个并行调用链的执行?

javascript - 如何从属性中收集信息并将它们作为数组发送?

c - 从 C 中的数组堆栈中弹出 - 将 NULL 分配给 int *

c - 如果使用用户定义函数和 main() 函数访问全局声明的数组元素,为什么会得到不同的值?

c++ - 单击窗口 - 然后会发生什么?

javascript - Javascript 对象中的属性范围

c - 如何知道数组的下一个空闲位置

c - 在c中将char指针写入控制台