【发布时间】:2015-03-26 19:08:02
【问题描述】:
动机:
几乎是为了好玩,我正在尝试编写一个函数重载,它可以区分参数是固定大小的数组还是指针。
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* 指针对编译器不那么明显:
- 一个奇怪的(便携?),(来自@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代替原始数组怎么样? -
@user657267,谢谢,我只想要一个不涉及更改主函数中的代码的解决方案。如果您想知道,原因是我想从指针产生的文本中分辨出硬编码文本 (
"hello")。 -
有一个奇怪的解决方法:coliru.stacked-crooked.com/a/37214a2859f7e78d 一个更明显的解决方案是使用标签调度。
-
你可以根据常量重载吗?
-
@Thomas,我在
main代码中尝试过,两者都是const,所以我认为无法利用它