【问题标题】:"size_t" as type parameter, cast warning not reproduced“size_t”作为类型参数,未复制强制转换警告
【发布时间】:2012-04-04 21:22:54
【问题描述】:

我一直试图摆脱一些旧代码中的警告(必须使用 MSVC 2005,目前正在使用 32 位构建),但一直在努力摆脱 size_t 到 @987654322 @转换警告。我们有自己的Array<T> 实现了一个不断增长的数组,它实现了一个

template<typename I> const T& at(const I i) const {return atImpl(i);}

方法。当被称为

size_t i = 10; myArray.at(i);

我收到conversion from 'size_t' to 'const unsigned int', possible loss of data 警告。 工作理论认为I 被理解为unsigned int,这导致编译器在将i 传递给at 时将size_t 转换/转换为unsigned int(这会很不方便,但可以接受)。但是,我无法在最小工作示例(本文底部)和更复杂的最小示例中重现此警告。只需将参数转换为 unsigned int 即可使警告消失,足以满足我们的需求(根据合同,该数字适合 unsigned int

  1. 我对 I 在这样的调用中的理解是否正确(规范说“typedef-name 因此是另一种类型的同义词。typedef-name 确实 不引入新类型”,typeid(size_t(1)).name()unsigned intsize_t 似乎是typedeffed)。换句话说,是否应该或不应该最小示例给出警告?构建配置是一样,据我所知。
  2. 由于我们的代码给了我们警告而最小的例子没有,所以我必须忽略一些事情。尽管付出了很多努力,但我无法弄清楚是什么。想法?

谢谢

最小的例子:

    template<typename T>
    class A
    {
      int t;
    public:
      template<typename I> T& at(const I i) { return t;}  
    };

    int main()
    {  
      size_t i = 10;
      A<int> a; 
      a.at(i) = 5; // no warning, why?
      return 0;
    }

【问题讨论】:

  • 您是否有机会使用/Wp64 选项?它会警告size_t 在 64 位模式下的大小不同,但 unsigned int 没有。
  • 如果您正在努力使代码可移植,您应该考虑在您的MyVector 类型上使用std::size_t,而不是考虑警告是否有意义。总有一天,您将更改架构(64 位),size_t 的大小可能不同,您将不得不返回并重新查看所有警告......当然,除非该参数不是用于访问容器,而是用于以其他形式存储。
  • 如果atImpl 采用unsigned,那么警告是否源于atImpl(i),它实际上在传递std::size_t 参数时会执行std::size_tunsigned 的转换?跨度>
  • 好的,问题:为什么你有自己的std::vector 实现?
  • @CharlesBailey 是的,我正在使用 /Wp64

标签: c++ templates visual-c++-2005 size-t visual-studio


【解决方案1】:

at 函数也是模板化的。 C++ 将尝试推断模板类型参数。这是您的代码中发生的情况,因为您没有在调用中指定类型,例如 a.at(1);

此代码将生成警告,因为它已将类型推断为 unsigned int,然后我们尝试传递 size_t

template <typename T>
class A
{
    int t;
    public:
        template<typename I> T& at(const I i)
        { return t;}
};

int main()
{
    unsigned int j = 5;
    size_t i = 10;
    A<int> a;

    a.at(j) = 4; // deduce template type as unsigned int
    a.at(i) = 5; // generate warning
    return 0;
}

编辑:我实际上在 VS 中尝试了这段代码,它会生成警告。

Edit2: 在我尝试过的代码中 size_t 和 unsigned int 也是 4 个字节。所以我做了一些挖掘。在旧版本的 VS 中 size_t 定义为 typedef __w64 unsigned int size_t '__w64' 现在已弃用,但用于标记在移动到 64 位平台时具有不同大小(例如 64 与 32)的类型。 __w64 导致编译器将size_t 视为不同的类型。

作为一个实验,我输入了自己的 unsigned int myint 并将 size_t i = 10 行更改为 myint i = 10

使用 typedef __w64 unsigned int myint 会生成警告,而 'typedef unsigned int myint` 不会生成警告。

【讨论】:

  • 我想就是这样。为了进一步参考,似乎由于size_t 在我的配置中等于unsigned intat(size_t(1))at((unsigned int)2) 都将实例化并重用at 的相同版本(因为两者都是我当前配置下的同义词)。如果使用a.at(j);a.at(i);,则会实例化atunsigned int 版本,然后,由于等价性,a.at(i); 引用会重用它,这会触发警告。如果使用a.at(i);a.at(j);,则size_t 版本为inst。并被a.at(j) 引用重用,没问题/警告。正确的?很棒的发现!
  • 这是一个很好的总结。如果首先调用 a.at(i) 也是正确的,当调用 a.at(j) 时 unsigned int 会提升为 size_t (unsigned long) 而不会丢失数据。
  • 实际上,需要明确的是,我说的是 32 位构建,其中 sizeof(i) == sizeof(j),所以不会有任何促销活动。据我所知,其余的仍然有效。
  • explicit 关键字在这种情况下有用吗?它甚至是有效的吗? (我用的不多,所以不确定。)
  • HazaB,我明白了。我想我会推迟到上面的 cmets。您的构建是否可能重新定义了 size_t?也许是有符号的值。
猜你喜欢
  • 2017-02-11
  • 1970-01-01
  • 2018-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多