繁体   English   中英

如何从std :: array中推导出数组大小 <T, N> ::指针成员/依赖类型?

[英]How to deduce array size out of std::array<T, N>::pointer member/dependent type?

我的目标是在编译期间知道目标缓冲区大小的情况下为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(), N, "%s", 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编写相同的问题。

命名空间std template<class T> arraydata()成员是 - 根据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 pointer = char*并编译(如果使用过pointer data()具有以下签名的虚构成员pointer 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 *);

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

你遇到的问题是std::array<char, N>::pointer所有N char* ,所以当你调用ys.data()你将char*传递给函数,并且有无限的N一切都好。 编译器将其视为模糊不清。 我看了一下array ,我看不出有什么方法可以创建你正在寻找的替代品。

但是,由于你正在编写C ++,你可以通过使用std::string而不是尝试处理C std::string来解决问题。

正如其他人所说, std::array中没有指针成员有关于大小的信息,特别是pointer没有该信息。

非常不便携的替代方法是在GNU C ++中使用._M_elems而不是.pointer

int main(){
  std::array<double, 10> arr;
  assert( std::extent<decltype(arr._M_elems)>() == arr.size() );
}

std::array应该有标准的carraycarray_type成员吗? 也许是的。 虽然这个变量会在指针中轻易衰减,但它不会非常有用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM