是否有可能重载一个函数,它可以告诉从一个指针固定数组? [英] Is it possible to overload a function that can tell a fixed array from a pointer?

查看:133
本文介绍了是否有可能重载一个函数,它可以告诉从一个指针固定数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

动机:

几乎为了好玩,我试图写一个函数重载,可以分辨的说法是否是一个固定大小的数组或一个指针。

 双常量D [] = {1,2,3};
双A;
双常量* p =&放大器;一个;
F(四); //调用数组版本
F(p)的; //调用指针版本

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

 无效F(字符常量* C){...}
模板<为size_t N'GT;无效F(字符常量(安培;一)[N]){...}

可惜,这是行不通的。因为在最好的情况下编译器确定数组调用 F(D)以上是模糊的。

部分解决:

我试了很多东西,我能得到最接近的是以下具体code。也是需要注意,在这个例子中code我用字符而不是双击,但它是非常相似结束。

首先,我必须在函数指针版本使用SFINAE禁用转换(从数组裁判PTR)。其次,我不得不超负荷所有可能的数组大小(手动)。

[编译code]

 #包括LT&;&type_traits GT; //为enable_if(在C ++ 98使用升压enable_if)
#包括LT&;&iostream的GT;
模板<类字符,类型名=类型名称的std :: enable_if<的std :: is_same<字符,字符> ::值> ::类型>
无效F(字符常量* DPTR){性病::法院LT&;< PTR<<的std :: ENDL;} // preferred似乎无效F(字符常量(安培; darr)[0]){性病::法院LT&;< 常量ARR<<的std :: ENDL;}
无效F(字符常量(安培; darr)[1]){性病::法院LT&;< 常量ARR<<的std :: ENDL;}
无效F(字符常量(安培; darr)[2]){性病::法院LT&;< 常量ARR<<的std :: ENDL;}
无效F(字符常量(安培; darr)[3]){性病::法院LT&;< 常量ARR<<的std :: ENDL;}
无效F(字符常量(安培; darr)[4]){性病::法院LT&;< 常量ARR<<的std :: ENDL;}
无效F(字符常量(安培; darr)[5]){性病::法院LT&;< 常量ARR<<的std :: ENDL;}
无效F(字符常量(安培; darr)[6]){性病::法院LT&;< 常量ARR<<性病:: ENDL;} //这是一个所谓的在此特定实例中
//循环往复......诠释主(){
    F(你好); //打印PTR,OK,因为这是固定大小的数组
    F(。的std ::字符串(你好)c_str()); //打印ARR,OK的,因为`c_str()`是一个指针
}

这工作,但问题是,我不得不重复功能的 N 和所有可能的值使用模板<为size_t N'GT; 让我又回到了起点为零,因为模板参数在两个通话回到平起平坐。在其他作品模板<为size_t N'GT;无效F(字符常量(安培;一)[N]){性病::法院LT&;< 常量ARR<<的std :: ENDL;} 没有帮助

有什么办法来概括第二过载而没有回落到一个模棱两可的电话吗?或者是有一些其他的方法呢?

一个C ++或C ++ 1XYZ回答也欢迎。

两个细节:1)我用上面的实验中,2)实际˚F将结束作为一个运营商的LT;< ,我想知道这是否会为解决重要


解决方案的摘要(根据其他人的下面)和适应例子的具体类型字符。似乎都取决于制作字符常量* 指针编译器不太明显的:

1),其中的怪异的(便携式),(从@dyp的注释)添加引用限定符指针的版本:

 模板<类字符,类型名=类型名称的std :: enable_if<的std :: is_same<字符,字符> ::值> ::类型>
无效F(字符常量* const的&安培; DPTR){性病::法院LT&;< PTR<<的std :: ENDL;}模板<为size_t N'GT;
无效F(字符常量(安培; darr)[N]){性病::法院LT&;< 常量ARR<<的std :: ENDL;}

2)一个优雅(特别从@ user657267情况下)

 模板<类CharConstPtr,类型名=类型名称的std :: enable_if<的std :: is_same< CharConstPtr,字符常量*> ::值> ::类型>
无效F(CharConstPtr DPTR){性病::法院LT&;< PTR<<的std :: ENDL;}模板<为size_t N'GT;
无效F(字符常量(安培; darr)[N]){性病::法院LT&;< 常量ARR<<的std :: ENDL;}


解决方案

这似乎为我工作

 的#include<&iostream的GT;模板< typename的T>
的std :: enable_if_t<的std :: is_pointer< T> ::值>
美孚(T){性病::法院LT&;< 指针\\ n; }模板< typename的T,性病::为size_t SZ>
无效美孚(T(安培)[深圳]){性病::法院LT&;< 数组\\ n; }诠释的main()
{
  字符常量* C;
  富(C);
  富(你好);
}

奖金的std ::实验:: type_traits

 使用的std ::实验:: is_pointer_v;
的std :: enable_if_t< is_pointer_v< T>>


您的评论让我尝试一些更简单

 模板< typename的T>无效美孚(T){性病::法院LT&;< 指针\\ n; }
模板< typename的T,无符号SZ>无效美孚(T(安培)[深圳]){性病::法院LT&;< 数组\\ n; }

当然,这里的问题是,现在可调用任何类型,取决于你希望你的参数检查要怎么涣散。


另一种方式是(AB)的使用右值引用

 无效美孚(字符常量*放大器;){性病::法院LT&;< 指针\\ n; }
无效美孚(字符常量*放大器;&安培;){性病::法院LT&;< 数组\\ n; }

显然,这不是万无一失的。

Motivation:

Almost for fun, I am trying to write a function overload that can tell apart whether the argument is a fixed-size array or a pointer.

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

I find this particularly difficult because of the well known fact that arrays decay to pointer sooner than later. A naive approach would be to write

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

Unfortunately this doesn't work. Because in the best case the compiler determines the array call f(d) above to be ambiguous.

Partial solution:

I tried many things and the closest I could get was the following concrete code. Note also that, in this example code I use char instead of double, but it is very similar at the end.

First, I have to use SFINAE to disable conversions (from array ref to ptr) in the pointer version of the function. Second I had to overload for all possible arrays sizes (manually).

[compilable code]

#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
}

This works, but the problem is that I have to repeat the function for all possible values of N and using template<size_t N> gets me back to square zero, because with the template parameter the two calls get back to equal footing. In other works template<size_t N> void f(char const(&a)[N]){std::cout << "const arr" << std::endl;} doesn't help.

Is there any way to generalize the second overload without falling back to an ambiguous call? or is there some other approach?

A C++ or C++1XYZ answer is also welcome.

Two details: 1) I used clang for the experiments above, 2) the actual f will end up being an operator<<, I think know if that will matter for the solution.


Summary of solutions (based on other people's below) and adapted to a the concrete type char of the example. Both seem to depend on making the char const* pointer less obvious for the compiler:

1) One weird (portable?), (from the comment of @dyp.) Adding a reference qualifier to the pointer version:

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

2) One elegant (special case from @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;}

解决方案

This seems to work for me

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

Bonus std::experimental::type_traits:

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


Your comment made me try something even simpler

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

Of course the problem here is that foo is now callable for any type, depends on how lax you want your parameter checking to be.


One other way is to (ab)use rvalue references

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

Obviously it's not foolproof.

这篇关于是否有可能重载一个函数,它可以告诉从一个指针固定数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆