微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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都将被“删除

原文地址:https://www.jb51.cc/c/118249.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐