加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 如何从std :: array :: pointer成员/依赖类型中推导出数组

发布时间:2020-12-16 07:15:13 所属栏目:百科 来源:网络整理
导读:我的目标是在编译期间知道目标缓冲区大小的情况下为strcpy编写安全替换,并且我希望推导出缓冲区大小,因此用户不需要知道它.例如: char xs[2] = { 0 };strcpy(xs,"abc"); // buffer overflow!printf("[%s]n",xs); 这个的输出(希望)是: [abc] 对于简单的情
我的目标是在编译期间知道目标缓冲区大小的情况下为strcpy编写安全替换,并且我希望推导出缓冲区大小,因此用户不需要知道它.例如:

char xs[2] = { 0 };
strcpy(xs,"abc"); // buffer overflow!
printf("[%s]n",xs);

这个的输出(希望)是:

[abc]

对于简单的情况,当传递C风格的数组时,可以毫不费力地编写它:

template<size_t N>
char * safe_strcpy(char (& dst)[N],const char * src) noexcept {
    std::snprintf(dst,N,"%s",src);
    return & dst[0];
}

推导出数组的大小,snprintf负责放置终止空字节,voilà.

我也可以将它改编为std :: array:

template<size_t N>
typename std::array<char,N>::pointer
safe_strcpy(std::array<char,N> & dst,const char * src) noexcept {
    std::snprintf(dst.data(),src);
    return dst.data();
}

但是这个版本并不是真正的替代品:

std::array<char,2> ys = {};
strcpy(ys.data(),"abc"); // overflow!
safe_strcpy(ys,"abc");   // ok,but I needed to remove .data()

我希望以下案例可以正常工作:

safe_strcpy(ys.data(),"abc"); // "a" should appear in buffer

依赖类型的ys.data()是std :: array< char,2u> :: pointer {aka char *},所以我认为应该可以从中推断出数组大小,但我无法弄清楚如何:/

当我尝试这样的事情时:

template<size_t N>
typename std::array<char,N>::pointer
safe_strcpy(typename std::array<char,N>::pointer & dst,const char * src) {
    // etc...
}

编译失败并出现错误:

error: no matching function for call to ‘safe_strcpy(std::array<char,2u>::pointer,const char [4])’
safe_strcpy(ys.data(),"abc");
                            ^
(...)
note:   template argument deduction/substitution failed:
note:   couldn't deduce template parameter ‘N’

我尝试使用gcc 5.1.1和clang 3.5.0,两者中的错误基本相同.是否有可能从C中推断出依赖类型的类型?

[编辑]
对你所有善良的人说,我应该使用std :: string – 你在这里错过了重点.我可以用任何STL容器和:: iterator而不是:: pointer编写相同的问题.

解决方法

模板< class T>的data()成员命名空间std中的数组是 – 根据C 11标准 – 声明如下

T * data() noexcept;
const T * data() const noexcept;

但不是这样的:

pointer data() noexcept;
const_pointer data() const noexcept;

即使使用typedef声明它也没有区别.考虑您的示例代码:

std::array<char,2> ys = {}; // 1
strcpy(ys.data(),"abc"); // 2
safe_strcpy(ys,"abc"); // 3

// 1

编译器实例化std :: array< char,2>.这使得typedef指针= char *并编译(如果使用过)具有以下签名的虚构成员指针data():

char* data();

typedef被替换,因为typedef和别名是程序员的语法糖 – 而不是编译器.编译器知道这是char *所以就是这样.

// 2

您使用(作为第一个参数)使用签名char *(void)的函数调用模板. (再次,std :: array< char,2> :: pointer不是它自己的类型,而是char *).因此,调用是void(char *,char const *),这就是编译器试图从中推导出模板的内容.并且此调用不会显示有关数组大小的任何信息,也不会知道指针首先来自数组的事实.

// 3

在这里你的电话是

void(std::array<char,2> &,char const *);

如果需要,编译器可以推断出大小甚至字符类型.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读