代码之家  ›  专栏  ›  技术社区  ›  Parker

Windows与Linux上std::string的可移植性和长度

  •  0
  • Parker  · 技术社区  · 5 年前

    我遇到了C++ 11的一些可移植性问题。 std::string 长度。在窗户上 long long unsigned int 但是在Linux和Mac上 long unsigned int . 我的理解是使用 auto 是解决此类问题的标准方法,但我很难找到通过类接口公开这些属性的可移植方法。


    以下类在LinuxGCC7.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
    

    束腰

    #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();
    }
    

    StrugRAPP.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 S to 汽车 -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
    

    当我使用 汽车 编译 --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::字符串 (如上所示)?

    3 回复  |  直到 5 年前
        1
  •  4
  •   NathanOliver    5 年前

    std::string 提供公共类型,例如 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();
    }
    

    如果你不想重复 标准::字符串::大小\类型 在整个地方,你可以向你的类中添加一个using声明来缩短名称,比如

    using pos_type = std::string::size_type;
    

    然后你就用 pos_type .

        2
  •  5
  •   Useless    5 年前

    看着 std::string 文档,您可以看到类型被调用

    std::string::size_type
    

    所以就用它吧。您不需要知道或猜测它是什么基元类型typedef 属于 -您已经有了一个可使用的名称,保证是正确的。

        3
  •  2
  •   Yakk - Adam Nevraumont    5 年前

    不能使用 auto 返回类型扣除。

    为了 读了你的心思,你就预告到:

    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)
    

    Live example .

    (作为附加奖金,

    template<class C>
    auto iterators_into( C& c ) {
      return indexes( c.begin(), c.end() );
    }
    

    也很有用,允许您在不手动写入 for(;;) 循环)