C++ 类模板中未发生隐式转换
我正在编写一个简单的基于std::数组的字符串类,如下所示。该类的行为应该非常有限,就像std::string一样,但所有数据都存储在堆栈上。此外,它几乎没有构造函数可以从const char*和std::string构造。代码如下:C++ 类模板中未发生隐式转换,c++,c++17,C++,C++17,我正在编写一个简单的基于std::数组的字符串类,如下所示。该类的行为应该非常有限,就像std::string一样,但所有数据都存储在堆栈上。此外,它几乎没有构造函数可以从const char*和std::string构造。代码如下: #ifndef SSTRING_H #define SSTRING_H #include <algorithm> #include <array> #include <cstring> #include <iterato
#ifndef SSTRING_H
#define SSTRING_H
#include <algorithm>
#include <array>
#include <cstring>
#include <iterator>
#include <ostream>
// friend operator declarations
template <typename CharT, std::size_t SizeT>
class basic_sstring;
template <typename CharT, std::size_t SizeT>
constexpr bool operator == (const basic_sstring<CharT, SizeT>&, const basic_sstring<CharT, SizeT>&);
template <typename CharT, std::size_t SizeT>
constexpr bool operator != (const basic_sstring<CharT, SizeT>&, const basic_sstring<CharT, SizeT>&);
template <typename CharT, std::size_t SizeT>
constexpr basic_sstring<CharT, SizeT> operator + (const basic_sstring<CharT, SizeT>&,
const basic_sstring<CharT, SizeT>&);
template <typename CharT, std::size_t SizeT>
std::basic_ostream<CharT>& operator << (std::basic_ostream<CharT>&, const basic_sstring<CharT, SizeT>&);
// basic_sstring class template
template <typename CharT, std::size_t SizeT = 512>
class basic_sstring
{
public:
typedef CharT value_type;
// constructor for empty basic_sstring
constexpr basic_sstring() : _size(0)
{
_data[_size] = static_cast<CharT>(0);
}
// constructor for const char* with a size specified
constexpr basic_sstring(const CharT* data_, std::size_t size_)
: _size(size_)
{
std::memcpy(&_data[0], data_, _size*sizeof(CharT));
_data[_size] = static_cast<CharT>(0);
}
// constructor for const char* which is null terminated
constexpr basic_sstring(const CharT* data_)
: _size(std::char_traits<CharT>::length(data_))
{
std::memcpy(&_data[0], data_, _size*sizeof(CharT));
_data[_size] = static_cast<CharT>(0);
}
// constructor for std::string
constexpr basic_sstring(const std::basic_string<CharT>& str_)
: _size(str_.size())
{
std::memcpy(&_data[0], str_.c_str(), _size*sizeof(CharT));
_data[_size] = static_cast<CharT>(0);
}
// default copy constructor
// default move constructor
// operators
// default copy assigment operator
// default move assigment operator
// comparison operators
constexpr friend bool operator == <> (const basic_sstring<CharT, SizeT>&, const basic_sstring<CharT, SizeT>&);
constexpr friend bool operator != <>(const basic_sstring<CharT, SizeT>&, const basic_sstring<CharT, SizeT>&);
// + operator
constexpr friend basic_sstring<CharT, SizeT> operator + <> (const basic_sstring<CharT, SizeT>&,
const basic_sstring<CharT, SizeT>&);
// += operator
constexpr basic_sstring<CharT, SizeT> operator += (const basic_sstring<CharT, SizeT>& other_)
{
return *this + other_;
}
// << operator
friend std::basic_ostream<CharT>& operator << <> (std::basic_ostream<CharT>&,
const basic_sstring<CharT, SizeT>&);
// reference to internal buffer
constexpr const CharT* data() const { return &_data[0]; };
// capacity
constexpr std::size_t capacity() { return SizeT; }
// size
constexpr std::size_t size() { return _size; };
private:
std::array<CharT, SizeT> _data;
std::size_t _size;
};
// == operator for basic_sstring
template <typename CharT, std::size_t SizeT>
constexpr bool operator == (const basic_sstring<CharT, SizeT>& first_,
const basic_sstring<CharT, SizeT>& second_)
{
return first_._size == second_._size && first_._data == second_._data;
}
// != operator for basic_sstring
template <typename CharT, std::size_t SizeT>
constexpr bool operator != (const basic_sstring<CharT, SizeT>& first_,
const basic_sstring<CharT, SizeT>& second_)
{
return !(first_ == second_);
}
// + operator for basic_sstring
template <typename CharT, std::size_t SizeT>
constexpr basic_sstring<CharT, SizeT> operator + (const basic_sstring<CharT, SizeT>& first_,
const basic_sstring<CharT, SizeT>& second_)
{
auto result = first_;
std::memcpy(&result._data[result._size], &second_._data[0], second_._size*sizeof(CharT));
result._size += second_._size;
result._data[result._size] = static_cast<CharT>(0);
return result;
}
// << operator for basic_sstring
template <typename CharT, std::size_t SizeT>
std::basic_ostream<CharT>& operator << (std::basic_ostream<CharT>& out,
const basic_sstring<CharT, SizeT>& sstr_)
{
std::copy(sstr_._data.begin(), sstr_._data.begin() + sstr_._size, std::ostreambuf_iterator<char>(out));
return out;
}
typedef basic_sstring<char> sstring;
#endif
\ifndef SSTRING\H
#定义字符串
#包括
#包括
#包括
#包括
#包括
//友元运算符声明
模板
类基本字符串;
模板
常量表达式布尔运算符==(常量基本字符串&,常量基本字符串&);
模板
constexpr布尔运算符!=(常量基本字符串&,常量基本字符串&);
模板
constexpr basic字符串运算符+(const basic字符串&,
常量基本字符串&);
模板
std::basic_ostream&operator模板推导发生在重载解析和任何可能的参数转换之前。所以你的接线员:
basic_sstring<CharT, SizeT> operator + (const basic_sstring<CharT, SizeT>& first_,
const basic_sstring<CharT, SizeT>& second_)
basic字符串运算符+(常量basic字符串和first字符串),
常量基本字符串和第二字符串)
除非编译器可以推导出这两个参数的CharT
和SizeT
,否则不会考虑。当然,当一个参数是文本时,它不能
“真实的”std::string
必须克服这一点。这也是我一直在努力解决的一件非常令人沮丧的事情。您将不得不尝试一种基于的方法:
template <typename T1, typename T2,
typename String1 = decltype(basic_sstring(std::declval<T1>())),
typename String2 = decltype(basic_sstring(std::declval<T2>()))>
constexpr bool operator==(const T1 &string1, const T2 &string2);
模板
constexpr bool运算符==(const T1和string1、const T2和string2);
它使用,因此您可能需要为基本的基于字符串的构造函数添加用户定义的演绎指南:
template <typename CharT>
basic_sstring(const std::basic_string<CharT>&) -> basic_sstring<CharT, 512>;
模板
基本字符串(const std::basic字符串&->basic字符串;
这意味着我需要为任何需要的转换创建重载,比如说const char*和std::string?有没有其他方法可以解决这个问题?我还认为所有需要的操作员都需要这样做?原则上,是的。问题是编译器首先收集可能的重载,然后才考虑参数的任何转换。如果无法推断模板参数,那么模板在第一轮中就已经被丢弃了。我觉得这很有趣(我对所有这些都比较陌生)。你有时间在(比如)放一个最小的现场演示吗?@PaulSanders,对不起,我没有。但是,如果你打算自己尝试这种方法,并遇到一些麻烦,请不要犹豫,要求澄清。好的,可能会尝试,视情况而定。谢谢。@r3mus n0x谢谢。现在可以用了。唯一的问题是sstring在每个操作符的定义中创建了参数的额外副本。但由于没有堆分配,这是可以的。
basic_sstring<CharT, SizeT> operator + (const basic_sstring<CharT, SizeT>& first_,
const basic_sstring<CharT, SizeT>& second_)
template <typename T1, typename T2,
typename String1 = decltype(basic_sstring(std::declval<T1>())),
typename String2 = decltype(basic_sstring(std::declval<T2>()))>
constexpr bool operator==(const T1 &string1, const T2 &string2);
template <typename CharT>
basic_sstring(const std::basic_string<CharT>&) -> basic_sstring<CharT, 512>;