动机:
我几乎是出于兴趣,正在尝试编写一个函数重载,可以区分参数是固定大小的数组还是指针。
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来禁用指针版本函数中的转换(从数组引用到指针)。其次,我必须手动重载所有可能的数组大小。
[可编译的代码]
#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*
指针对编译器不太明显:
- 一种奇怪(可移植?)的方法(来自@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;}
- 一个优雅的例子(@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;}
std::array
代替原始数组怎么样? - user657267void f(char const* const& dptr){std::cout << "ptr" << std::endl;}
并不能解决问题。至少在我的clang++
中是这样的。 - alfC