C++ 带有取消引用类型双关指针的stof()/stoi()将打破严格的别名规则

C++ 带有取消引用类型双关指针的stof()/stoi()将打破严格的别名规则,c++,casting,stl,std,C++,Casting,Stl,Std,我有自己的类型 namespace FaF { // Allocator is my own Memory Allocator for STL using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>; } FaF::string number("1234"); stoi( (const std::string &) number);

我有自己的类型

namespace FaF
{
    // Allocator is my own Memory Allocator for STL
    using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
}

FaF::string number("1234");
stoi( (const std::string &) number);  <-- error
名称空间FaF
{
//分配器是我自己的STL内存分配器
使用string=std::basic_字符串;
}
FaF::字符串编号(“1234”);

stoi((const std::string&)编号) 使用
c_str
和atoi代替:

FaF::string number("1234");
int result = atoi(number.c_str()); // result == 1234

这是
sto*
函数类的一个不幸问题;它们仅适用于
std::string
。即使他们不关心你使用的分配器,但仍然是类型的一部分,所以它仍然对C++重要。您也不能假装使用不同分配器的
basic_string
std::string

在C++17之前,您必须手动处理它:

stoi({number.data(), number.size()});

不能将字符串与sto*函数一起使用。如果您查看docs(),您会发现函数的签名正好是std::string。在哪里

std::string = std::basic_string<char, class Traits = std::char_traits<CharT>, 
    class Allocator = std::allocator<CharT>>
std::string=std::basic\u string
我想提醒您注意,它使用标准分配器。因此,实际上您的字符串与std::string不同

作为一种解决方法,您可以指定std::string运算符

struct string : public std::basic_string<char, std::char_traits<char>, Allocator<char>>
{
    // will produce a copy. use const char* instead
    explicit operator std::string()
    {
        return c_str();
    }
    explicit operator const char*()
    {
        return c_str();
    }
};
结构字符串:公共标准::基本字符串 { //将生成一个副本。请改用常量字符* 显式运算符std::string() { 返回c_str(); } 显式运算符const char*() { 返回c_str(); } };
用法示例:

FaF::string number( "1435151315" );
std::cout << std::stoi( static_cast< std::string >( number ) );
std::cout << std::atoi( static_cast< const char* >( number ) );
FaF::字符串编号(“14351315”);
std::cout(number));
std::cout(number));
PS:不要使用C样式转换!:)

我希望它能有所帮助。

在学习了
basic_string.h
std::stoi
的定义之后:

inline int
stoi(const string& __str, size_t* __idx = 0, int __base = 10)
{ return __gnu_cxx::__stoa<long, int>(&std::strtol, "stoi", __str.c_str(),
                    __idx, __base); }
inline int
stoi(常量字符串和字符串,大小\u t*\u idx=0,整数\u基数=10)
{return uu gnu cxx::u stoa(&std::strtol,“stoi”,uu str.c_str(),
__idx,_基);}
然后,我就很容易编写自己的——更一般的——版本:

namespace FaF
{
  template<typename T>
  inline int
  stoi(const T& __str, size_t* __idx = 0, int __base = 10)
  { return __gnu_cxx::__stoa<long, int>(&std::strtol, "stoi", __str.c_str(),
                    __idx, __base); }
}
名称空间FaF
{
模板
内联整数
stoi(常数T和常数str,大小T*\UUUIdx=0,整数基数=10)
{return uu gnu cxx::u stoa(&std::strtol,“stoi”,uu str.c_str(),
__idx,_基);}
}
这个测试脚本

FaF::string numberFaF( "1234" );
std::string numberStd( "4321" );
printf( "stoi<FaF::string>=%d - stoi<std::string>=%d\n", 
              FaF::stoi( numberFaF ), FaF::stoi( numberStd ) );
FaF::字符串numberFaF(“1234”);
std::字符串编号std(“4321”);
printf(“stoi=%d-stoi=%d\n”,
FaF::stoi(numberFaF),FaF::stoi(numberStd));
编译并生成预期结果:

stoi<FaF::string>=1234 - stoi<std::string>=4321
stoi=1234-stoi=4321

我只是想知道为什么还没有一个通用的版本。STL中的几乎所有内容都是作为模板实现的,这个简单的函数被硬编码为
std::string

关键在于:这两种类型不一样,句号。你不能把一个抛给另一个。这不仅仅是一个理论问题,例如,
sizeof(std::allocator)!=sizeof(您的::分配器)
@erenon好的,这意味着我必须编写自己版本的
stoi()/stof()
,比如
FaF::stoi()/FaF::stof()
?作为替代,您也可以将字符串复制到常规字符串中。@erenon是的,我在考虑这个问题,但我认为最好将它封装到我自己的
名称空间
函数
“然后就可以很容易地编写我自己的更通用的版本:”它只在一个实现上工作,因为你调用的是非标准函数。@Nicolas??我不明白。它完全是gcc提供的
basic_string.h
的副本-只需将其包装到模板中即可;这就是问题所在。它只适用于GCC<代码>\uuuu gnu\ucxx不存在于,例如libc++.@nicolas:-);我现在抓到你了。由于环境的原因,我和gcc结婚了。这是一个非常特殊的项目,不会部署在其他系统上。到目前为止,对我来说还可以。谢谢你指出这一点!你能简要总结一下C++17是如何解决这个问题的吗?C++17的代码段是什么?