std::string 在 Windows 与 Linux 上的便携性和长度
Portability and length of std::string on Windows vs. Linux
我 运行 遇到了 C++11 std::string
长度的一些可移植性问题。在 Windows 上它是 long long unsigned int
但在 Linux 和 Mac 上它是 long unsigned int
。我的理解是,使用 auto
是解决此类问题的标准方法,但我很难找到一种可移植的方法来通过 class 接口公开这些属性。
以下 class 在 Linux GCC 7.3.0(以及 MacOS 上编译和运行没有问题:
g++ -g -O2 -std=c++11 -Werror=conversion stringwrap.cc
./a.out
3
但是在 Windows (g++ 8.1.0 MinGW-W64 x86_64-posix-seh-rev0) 上,我得到以下编译错误:
C:\temp\v0.11>g++ -g -O2 -std=c++11 -Werror=conversion stringwrap.cc
In file included from stringwrap.cc:1:
stringwrap.h: In function 'long unsigned int determineFirstPosition(std::__cxx11::string)':
stringwrap.h:35:20: error: conversion from 'std::__cxx11::basic_string<char>::size_type' {aka 'long long unsigned int'}
to 'long unsigned int' may change value [-Werror=conversion]
return s.length();
~~~~~~~~^~
stringwrap.cc: In member function 'long unsigned int Stringwrap::length() const':
stringwrap.cc:9:23: error: conversion from 'std::__cxx11::basic_string<char>::size_type' {aka 'long long unsigned int'}
to 'long unsigned int' may change value [-Werror=conversion]
return str_.length();
~~~~~~~~~~~^~
cc1plus.exe: some warnings being treated as errors
stringwrap.h
#include <iostream>
#include <string>
class Stringwrap
{
private:
std::string str_;
public:
Stringwrap(const std::string& str);
unsigned long int length() const;
unsigned long int getFirstPosition() const;
};
inline unsigned long int determineFirstPosition(const std::string s)
{
for (unsigned long int i = 0; i < s.length(); ++i)
{
switch (s.at(i))
{
case ' ':
{
break;
}
default:
{
return i;
}
}
}
return s.length();
}
stringwrap.cc
#include "stringwrap.h"
Stringwrap::Stringwrap(const std::string& str) : str_(str)
{
}
unsigned long int Stringwrap::length() const
{
return str_.length();
}
unsigned long int Stringwrap::getFirstPosition() const
{
return determineFirstPosition(str_);
}
int main()
{
Stringwrap sw = *new Stringwrap(" x ");
std::cout << sw.getFirstPosition() << std::endl;
}
我已尝试将所有 unsigned long int
更改为 auto
,但使用 -std=c++11
时出现以下错误:
C:\temp\v0.11>g++ -g -O2 -std=c++11 -Werror=conversion stringwrap.cc
In file included from stringwrap.cc:1:
stringwrap.h:13:19: error: 'length' function uses 'auto' type specifier without trailing return type
auto length() const;
^~~~~
stringwrap.h:13:19: note: deduced return type only available with -std=c++14 or -std=gnu++14
stringwrap.h:15:29: error: 'getFirstPosition' function uses 'auto' type specifier without trailing return type
auto getFirstPosition() const;
^~~~~
stringwrap.h:15:29: note: deduced return type only available with -std=c++14 or -std=gnu++14
stringwrap.h:18:55: error: 'determineFirstPosition' function uses 'auto' type specifier without trailing return type
inline auto determineFirstPosition(const std::string s)
^
stringwrap.h:18:55: note: deduced return type only available with -std=c++14 or -std=gnu++14
stringwrap.h: In function 'auto determineFirstPosition(std::__cxx11::string)':
stringwrap.h:35:21: error: inconsistent deduction for auto return type: 'int' and then 'long long unsigned int'
return s.length();
^
stringwrap.cc: At global scope:
stringwrap.cc:7:27: error: 'length' function uses 'auto' type specifier without trailing return type
auto Stringwrap::length() const
^~~~~
stringwrap.cc:7:27: note: deduced return type only available with -std=c++14 or -std=gnu++14
stringwrap.cc:12:37: error: 'getFirstPosition' function uses 'auto' type specifier without trailing return type
auto Stringwrap::getFirstPosition() const
^~~~~
stringwrap.cc:12:37: note: deduced return type only available with -std=c++14 or -std=gnu++14
当我使用auto
并编译--std=c++14
时,出现以下错误:
C:\temp\v0.11>g++ -g -O2 -std=c++14 -Werror=conversion stringwrap.cc
In file included from stringwrap.cc:1:
stringwrap.h: In function 'auto determineFirstPosition(std::__cxx11::string)':
stringwrap.h:35:21: error: inconsistent deduction for auto return type: 'int' and then 'long long unsigned int'
return s.length();
^
问题:我如何编写可移植的 C++11 代码(Linux、Windows)来避免 STL 数据类型中的类型转换,例如 std::string
(如上所示)?
查看std::string
文档,可以看到类型叫做
std::string::size_type
所以就用那个吧。您不需要知道或猜测它是什么原始类型 typedef of - 您已经有了一个保证正确的可用名称。
std::string
提供 public 类型,例如 std::string::size_type
,您可以使用它们来定义函数。您可以像
这样定义 determineFirstPosition
函数
inline std::string::size_type determineFirstPosition(const std::string s)
{
for (std::string::size_type i = 0; i < s.length(); ++i)
{
switch (s.at(i))
{
case ' ':
{
break;
}
default:
{
return i;
}
}
}
return s.length();
}
如果您不想到处重复 std::string::size_type
,您可以在 class 中添加 using 声明以缩短名称,例如
using pos_type = std::string::size_type;
然后你就可以使用 pos_type
.
c++11 不能使用 auto
return 类型推导。
对于 c++14,读懂你的想法,你移植了这个:
inline unsigned long int determineFirstPosition(const std::string s)
{
for (unsigned long int i = 0; i < s.length(); ++i)
{
switch (s.at(i))
{
case ' ':
{
break;
}
default:
{
return i;
}
}
}
return s.length();
}
至
inline auto determineFirstPosition(const std::string s)
{
for (auto i = 0; i < s.length(); ++i)
{
switch (s.at(i))
{
case ' ':
{
break;
}
default:
{
return i;
}
}
}
return s.length();
}
在这种情况下,您的错误是
for (auto i = 0; i < s.length(); ++i)
因为auto i = 0
是int
,不是s.length()
的类型。
做
for (decltype(s.length()) i = 0; i < s.length(); ++i)
如果您想避免在此处命名类型。
或者,您可以使用 std::string::size_type
。或者,您可以编写一个实用程序,让您 for(:)
对某些内容进行索引;
template<class T> struct tag_t {using type=T;};
template<class X> using block_deduction = typename tag_t<X>::type;
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
};
template<class S>
struct indexer_t {
S s;
void operator++(){++s;}
S operator*() const{ return s; }
friend bool operator==( indexer_t const& lhs, indexer_t const& rhs ) {
return lhs.s == rhs.s;
}
friend bool operator!=( indexer_t const& lhs, indexer_t const& rhs ) {
return lhs.s != rhs.s;
}
};
template<class S>
range_t<indexer_t<S>> indexes( block_deduction<S> start, S finish ) {
return {{std::move(start)}, {std::move(finish)}};
}
template<class C>
auto indexes_into( C&& c ) {
return indexes( 0, c.size() );
}
所有这些都可以让你做到:
for( auto i : indexs_into(s) )
而不是
for (unsigned long int i = 0; i < s.length(); ++i)
(作为额外奖励,
template<class C>
auto iterators_into( C& c ) {
return indexes( c.begin(), c.end() );
}
也很有用,允许您将所有有效迭代器迭代到容器中,而无需手动编写 for(;;)
循环)
我 运行 遇到了 C++11 std::string
长度的一些可移植性问题。在 Windows 上它是 long long unsigned int
但在 Linux 和 Mac 上它是 long unsigned int
。我的理解是,使用 auto
是解决此类问题的标准方法,但我很难找到一种可移植的方法来通过 class 接口公开这些属性。
以下 class 在 Linux GCC 7.3.0(以及 MacOS 上编译和运行没有问题:
g++ -g -O2 -std=c++11 -Werror=conversion stringwrap.cc
./a.out
3
但是在 Windows (g++ 8.1.0 MinGW-W64 x86_64-posix-seh-rev0) 上,我得到以下编译错误:
C:\temp\v0.11>g++ -g -O2 -std=c++11 -Werror=conversion stringwrap.cc
In file included from stringwrap.cc:1:
stringwrap.h: In function 'long unsigned int determineFirstPosition(std::__cxx11::string)':
stringwrap.h:35:20: error: conversion from 'std::__cxx11::basic_string<char>::size_type' {aka 'long long unsigned int'}
to 'long unsigned int' may change value [-Werror=conversion]
return s.length();
~~~~~~~~^~
stringwrap.cc: In member function 'long unsigned int Stringwrap::length() const':
stringwrap.cc:9:23: error: conversion from 'std::__cxx11::basic_string<char>::size_type' {aka 'long long unsigned int'}
to 'long unsigned int' may change value [-Werror=conversion]
return str_.length();
~~~~~~~~~~~^~
cc1plus.exe: some warnings being treated as errors
stringwrap.h
#include <iostream>
#include <string>
class Stringwrap
{
private:
std::string str_;
public:
Stringwrap(const std::string& str);
unsigned long int length() const;
unsigned long int getFirstPosition() const;
};
inline unsigned long int determineFirstPosition(const std::string s)
{
for (unsigned long int i = 0; i < s.length(); ++i)
{
switch (s.at(i))
{
case ' ':
{
break;
}
default:
{
return i;
}
}
}
return s.length();
}
stringwrap.cc
#include "stringwrap.h"
Stringwrap::Stringwrap(const std::string& str) : str_(str)
{
}
unsigned long int Stringwrap::length() const
{
return str_.length();
}
unsigned long int Stringwrap::getFirstPosition() const
{
return determineFirstPosition(str_);
}
int main()
{
Stringwrap sw = *new Stringwrap(" x ");
std::cout << sw.getFirstPosition() << std::endl;
}
我已尝试将所有 unsigned long int
更改为 auto
,但使用 -std=c++11
时出现以下错误:
C:\temp\v0.11>g++ -g -O2 -std=c++11 -Werror=conversion stringwrap.cc
In file included from stringwrap.cc:1:
stringwrap.h:13:19: error: 'length' function uses 'auto' type specifier without trailing return type
auto length() const;
^~~~~
stringwrap.h:13:19: note: deduced return type only available with -std=c++14 or -std=gnu++14
stringwrap.h:15:29: error: 'getFirstPosition' function uses 'auto' type specifier without trailing return type
auto getFirstPosition() const;
^~~~~
stringwrap.h:15:29: note: deduced return type only available with -std=c++14 or -std=gnu++14
stringwrap.h:18:55: error: 'determineFirstPosition' function uses 'auto' type specifier without trailing return type
inline auto determineFirstPosition(const std::string s)
^
stringwrap.h:18:55: note: deduced return type only available with -std=c++14 or -std=gnu++14
stringwrap.h: In function 'auto determineFirstPosition(std::__cxx11::string)':
stringwrap.h:35:21: error: inconsistent deduction for auto return type: 'int' and then 'long long unsigned int'
return s.length();
^
stringwrap.cc: At global scope:
stringwrap.cc:7:27: error: 'length' function uses 'auto' type specifier without trailing return type
auto Stringwrap::length() const
^~~~~
stringwrap.cc:7:27: note: deduced return type only available with -std=c++14 or -std=gnu++14
stringwrap.cc:12:37: error: 'getFirstPosition' function uses 'auto' type specifier without trailing return type
auto Stringwrap::getFirstPosition() const
^~~~~
stringwrap.cc:12:37: note: deduced return type only available with -std=c++14 or -std=gnu++14
当我使用auto
并编译--std=c++14
时,出现以下错误:
C:\temp\v0.11>g++ -g -O2 -std=c++14 -Werror=conversion stringwrap.cc
In file included from stringwrap.cc:1:
stringwrap.h: In function 'auto determineFirstPosition(std::__cxx11::string)':
stringwrap.h:35:21: error: inconsistent deduction for auto return type: 'int' and then 'long long unsigned int'
return s.length();
^
问题:我如何编写可移植的 C++11 代码(Linux、Windows)来避免 STL 数据类型中的类型转换,例如 std::string
(如上所示)?
查看std::string
文档,可以看到类型叫做
std::string::size_type
所以就用那个吧。您不需要知道或猜测它是什么原始类型 typedef of - 您已经有了一个保证正确的可用名称。
std::string
提供 public 类型,例如 std::string::size_type
,您可以使用它们来定义函数。您可以像
determineFirstPosition
函数
inline std::string::size_type determineFirstPosition(const std::string s)
{
for (std::string::size_type i = 0; i < s.length(); ++i)
{
switch (s.at(i))
{
case ' ':
{
break;
}
default:
{
return i;
}
}
}
return s.length();
}
如果您不想到处重复 std::string::size_type
,您可以在 class 中添加 using 声明以缩短名称,例如
using pos_type = std::string::size_type;
然后你就可以使用 pos_type
.
c++11 不能使用 auto
return 类型推导。
对于 c++14,读懂你的想法,你移植了这个:
inline unsigned long int determineFirstPosition(const std::string s)
{
for (unsigned long int i = 0; i < s.length(); ++i)
{
switch (s.at(i))
{
case ' ':
{
break;
}
default:
{
return i;
}
}
}
return s.length();
}
至
inline auto determineFirstPosition(const std::string s)
{
for (auto i = 0; i < s.length(); ++i)
{
switch (s.at(i))
{
case ' ':
{
break;
}
default:
{
return i;
}
}
}
return s.length();
}
在这种情况下,您的错误是
for (auto i = 0; i < s.length(); ++i)
因为auto i = 0
是int
,不是s.length()
的类型。
做
for (decltype(s.length()) i = 0; i < s.length(); ++i)
如果您想避免在此处命名类型。
或者,您可以使用 std::string::size_type
。或者,您可以编写一个实用程序,让您 for(:)
对某些内容进行索引;
template<class T> struct tag_t {using type=T;};
template<class X> using block_deduction = typename tag_t<X>::type;
template<class It>
struct range_t {
It b, e;
It begin() const { return b; }
It end() const { return e; }
};
template<class S>
struct indexer_t {
S s;
void operator++(){++s;}
S operator*() const{ return s; }
friend bool operator==( indexer_t const& lhs, indexer_t const& rhs ) {
return lhs.s == rhs.s;
}
friend bool operator!=( indexer_t const& lhs, indexer_t const& rhs ) {
return lhs.s != rhs.s;
}
};
template<class S>
range_t<indexer_t<S>> indexes( block_deduction<S> start, S finish ) {
return {{std::move(start)}, {std::move(finish)}};
}
template<class C>
auto indexes_into( C&& c ) {
return indexes( 0, c.size() );
}
所有这些都可以让你做到:
for( auto i : indexs_into(s) )
而不是
for (unsigned long int i = 0; i < s.length(); ++i)
(作为额外奖励,
template<class C>
auto iterators_into( C& c ) {
return indexes( c.begin(), c.end() );
}
也很有用,允许您将所有有效迭代器迭代到容器中,而无需手动编写 for(;;)
循环)