【问题标题】:How to prevent implicit conversion from int to unsigned int?如何防止从 int 到 unsigned int 的隐式转换?
【发布时间】:2016-07-09 19:02:35
【问题描述】:

假设你有这个:

struct Foo {
    Foo(unsigned int x) : x(x) {}
    unsigned int x;
};

int main() {
    Foo f = Foo(-1);     // how to get a compiler error here?
    std::cout << f.x << std::endl;
}

是否可以防止隐式转换?

我能想到的唯一方法是明确提供一个构造函数,该构造函数接受 int 并在 int 为负数时生成某种运行时错误,但如果我能得到一个编译器错误会更好这个。

我几乎可以肯定,存在重复,但我能找到的最接近的是this question,它询问为什么允许隐式转换。

我对 C++11 和 C++11 之前的解决方案都感兴趣,最好是两者都适用的解决方案。

【问题讨论】:

    标签: c++ implicit-conversion unsigned-integer


    【解决方案1】:

    您可以通过删除不需要的重载来强制编译错误。

    Foo(int x) = delete;
    

    【讨论】:

    • Foo f(42) 将被禁止(即使42 是肯定的)(而Foo f(42u) 有效)。
    • @Jarod42,真的。但不可避免:)
    • @Sergey 对于编译时常量,我猜我们可以通过一些 SFINAE 重载和辅助方法来避免它,但我认为不能将这两种方法结合起来,因为通常不允许使用 int,但允许使用 int 常量.
    【解决方案2】:

    统一初始化防止变窄。

    它遵循一个(不按要求工作)示例:

    struct Foo {
        explicit Foo(unsigned int x) : x(x) {}
        unsigned int x;
    };
    
    int main() {
        Foo f = Foo{-1};
        std::cout << f.x << std::endl;
    }
    

    尽可能地习惯使用统一初始化(Foo{-1} 而不是Foo(-1))。

    编辑

    作为替代方案,根据 cmets 中 OP 的要求,也适用于 C++98 的解决方案是将构造函数声明为 private,从而获得 intlong int 等)。
    实际上不需要定义它们。
    请注意,= delete 也是一个很好的解决方案,正如另一个答案中所建议的那样,但这也是从 C++11 开始的。

    编辑 2

    我想再添加一个解决方案,尽管它从 C++11 开始就有效。
    该想法基于 Voo 的建议(有关更多详细信息,请参阅 Brian 的响应的 cmets),并在构造函数的参数上使用 SFINAE。
    它遵循一个最小的工作示例:

    #include<type_traits>
    
    struct S {
        template<class T, typename = typename std::enable_if<std::is_unsigned<T>::value>::type>
        S(T t) { }
    };
    
    int main() {
        S s1{42u};
        // S s2{42}; // this doesn't work
        // S s3{-1}; // this doesn't work
    }
    

    【讨论】:

    • 只能在 c++11 中使用,不是吗?
    • 是的,你是说不能用C++11吗?
    • @tobi303 我通常希望不使用统一初始化的开发人员也知道缺点是什么。例如,缩小。你不能强迫其他人写出好的代码。 :-)
    • @tobi303 " 但是如果存在一个在 c++11 前和 c++11 后都能很好地工作的解决方案,我更喜欢那个" private: Foo(int x); 怎么样?
    • @JesperJuhl ideone 没有抱怨explicit constructor called via Foo(-1)。我不得不承认我对大多数 c++11 的东西完全不熟悉
    【解决方案3】:

    如果您希望在每次 出现此类代码时收到警告,并且您正在使用 GCC,请使用 -Wsign-conversion 选项。

    foo.cc: In function ‘int main()’:
    foo.cc:8:19: warning: negative integer implicitly converted to unsigned type [-Wsign-conversion]
         Foo f = Foo(-1);     // how to get a compiler error here?
                       ^
    

    如果您想出错,请使用-Werror=sign-conversion

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-09
      • 2014-04-05
      • 2013-09-03
      • 2012-07-11
      • 2021-01-02
      • 1970-01-01
      • 2012-04-28
      • 1970-01-01
      相关资源
      最近更新 更多