c – 接口设计:采用字符串和字符串数组的重载函数的安全性

假设我们有一个可以将东西写入输出的类
class Writer
{
public:
    int write(const std::string& str);
    int write(const char* str,int len);
    //...
};

我很好,这很灵活,所有这一切,直到我意识到

char* buf = new char[n]; //not terminated with '\0'
//load up buf
Writer w;
w.write(buf);  //compiles!

这是一个非常讨厌的bug.

我们可以用一些模板来修改

class WriterV2
{
public:
    int write(const std::string& str);
    int write(const char* str,int len);
    template<typename... Args>
    int write(const char*,Args...)
    { static_assert(sizeof...(Args) < 0,"Incorrect arguments"); }
    //...
};

但这种方法存在问题

WriterV2 w;
w.write("The templating genius!"); //compile error

我该怎么办?什么是更好的设计?

在有人要求之前,重载为const char(&)[N] does not work.创建一个包装器来实现这一点可能是可行的,但这看起来……有点过分了吗?

编辑添加方法write(char *)并发出错误并不理想.当通过函数和所有这些传递buf时,它可能变成const char *.

解决方法

在C中的重载分辨率期间 ICS (Implicit Conversion Sequences)可以产生令人惊讶的结果,你已经注意到了,也很烦人..

您可以提供所需的必要接口,然后通过利用partial ordering删除不需要的重载,仔细使用模板来处理字符串文字与const char * fiasco.

码:

#include <iostream>
#include <string>
#include <type_traits>

class Writer
{
public:
    int write(std::string&&) { std::cout << "int write(std::string)\n"; return 0; }
    int write(const std::string&) { std::cout << "int write(const std::string& str)\n"; return 0; }
    int write(const char*,int){ std::cout << "int write(const char* str,int len)\n"; return 0; }

    template<std::size_t N = 0,typename = std::enable_if_t<(N > 0)> >
    int write(const char (&)[N]) { std::cout << "int write(string-literal) " << N << " \n"; return 0; }


    template<typename T>
    int write(T&&) = delete;

};

int main(){
    char* buf = new char[30];
    const char* cbuf = buf;
    Writer w;

    //w.write(buf);                     //Fails! 
    //w.write(cbuf);                    //Fails! 
    w.write(buf,30);                   //Ok!    int write(const char*,int);
    w.write(std::string("Haha"));       //Ok!    int write(std::string&&);
    w.write("This is cool");            //Ok!    int write(const char (&)[13]);
}

打印:

int write(const char* str,int len)
int write(std::string)
int write(string-literal) 13

Demo

请注意,上述解决方案继承了“使用无约束转发引用重载函数”的缺点.这意味着过载集中可行函数的参数类型的所有ICS都将被“删除

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...