当前位置: 首页 > 知识库问答 >
问题:

为什么我不能防止不希望的C样式强制转换编译?

崔单弓
2023-03-14

有一个不希望的C样式强制转换,我无法防止编译。不需要的强制转换执行从某个类的对象到其他类的非常量引用的C样式强制转换。这些类是不相关的。同时,我喜欢支持从同一个类的对象到常量引用的C样式转换。我提供了一个公共转换操作符来支持理想的强制转换。在这种情况下,似乎无法防止不希望的强制转换。
对非常量引用的强制转换未能生成(“Sandbox::B::操作符Sandbox::A&()”(在第30行声明)不可访问*),不幸的是,对常量引用的强制转换要么失败(错误:从“Sandbox::B”到“常量Sandbox::A”Application:function“Sandbox::B::操作符常量Sandbox::A&()”function“Sandbox::B::A&()”的多个转换函数“Sandbox::B::A&()”):

#include <iostream>
#include <string>
#include <cstdlib>

namespace Sandbox {
    class A {
    public:
        A (int i) : _x (i) { }
    private:
        int _x;
    };

    class B {
    public:
        B (const char* m) : _m (m), _a (std::atoi (m)) { }

        /*
         * This one shall be supported.
         */ 
        operator const A& () {
            return _a;
        }
    private:
        /*
         * This one shall be not supported.
         * If this one is disabled both desired and undesired conversions pass the compilation.
         */ 
        operator A& ();

        const std::string _m;
        const A _a;
    };
}

int main () {
    Sandbox::A a (1973);
    Sandbox::B b ("1984");

    /*
     * This is the undesirable cast and it shall fail to compile.
     */
    (Sandbox::A&)b;
    /*
     * This is the desirable cast and it shall pass the compilation.
     */
    (const Sandbox::A&)b;

    return 0;
}

如果禁用运算符运算符a&()将生成所需和不需的转换。

我正在使用gcc,icc和MSVC编译。我不能控制客户端代码和防止使用C风格的强制转换。

共有1个答案

东郭京
2023-03-14

这应该能起到作用(在Clang3.5上测试过):

#include <iostream>
#include <string>
#include <cstdlib>

namespace Sandbox {
  class A {
  public:
    A (int i) : _x (i) { }

    void        fun()
    {
      std::cout << "action" << std::endl;
    }

  private:
    int _x;
  };

  class B {
  public:
    B (const char* m) : _m (m), _a (std::atoi (m)) { }

    /*
     * This one shall be supported.
     */
    template<typename T, typename Enable = typename std::enable_if<std::is_same<T, A>::value, A>::type>
    operator const T& ()
    {
      return _a;
    }

    /*
     * This one shall be not supported.
     * If this one is disabled both desired and undesired conversions pass the compilation.
     */
  private:
    template<typename T, typename Enable = typename std::enable_if<std::is_same<T, A>::value, A>::type>
    operator T& ();

    const std::string _m;
    const A _a;
  };
}

int main () {
  Sandbox::A a (1973);
  Sandbox::B b ("1984");

  /*
   * This is the undesirable cast and it shall fail to compile.
   */
  (Sandbox::A&)b;

  /*
   * This is the desirable cast and it shall pass the compilation.
   */
  (const Sandbox::A&)b;

  return 0;
}

至于为什么你的版本不做你想做的事情,这与C风格演员阵容的规则有关:

当遇到C样式的强制转换表达式时,编译器将按以下顺序尝试执行以下强制转换表达式:

a)const_cast(表达式)

免责声明:这个解释主要是基于猜测,有多个步骤和复杂的规则,所以我不确定所有的工作真的像我认为我已经理解的那样,但给你。

由于强制转换为引用,reexpert_cast将始终基于其类型别名规则工作,因此使C样式强制转换失败的唯一方法是使该类型的static_cast明确地产生错误。不幸的是,转换规则似乎并不认为用户定义到const类型的转换比用户定义到非CV限定类型的转换更匹配,即使static_cast目标类型是const限定的,它们也在同一级别上。然而,使用模板、SFINAE和参数推断,以及从山龙中提取一些神奇的编译器粉末,它就可以工作了。(是的,这一步对我来说也有点神秘)。

 类似资料:
  • 问题内容: 执行此强制转换时出现编译错误: 应该被继承,尽管不能直接继承。 从文档: 农具其中inturn & 为什么这无效? 也感谢您提供有关使用as 的正确方法的意见? 我正在考虑包装方法。 问题答案: 扩展,并且 不 扩展。 如果您想从中获得帮助,我认为实现包装器类是您最简单的选择。幸运的是的唯一抽象方法是。 RandomAccessFile实现了DataInput,该数据输入将依次转为Da

  • 问题内容: 所以这工作: 但这不是: 总而言之,我得到了第一部分(拳击),但是我发现第二部分不起作用是非常不直观的。是否有特定的原因(除了String从Object继承而int不从Object继承)? 编辑: 为了完善我的问题,这也可以: 但是,以下内容却没有: 令人惊讶的是,您遇到了与String相同的问题: 在最后一行产生类强制转换异常。仍然有效: 问题答案: 我刚刚找到了我正在寻找自己的答案

  • 问题内容: 我在一个新项目中将Swift样板代码用于Core Data。我的文件有一个定义的单一实体()和一个属性()。 我有一个看起来像这样的文件: 当我运行它时,它起作用: 我什至可以进入iOS模拟器正在使用的SQLite数据库,并确认已添加该行。 但是,当我运行与上面完全相同的代码,但使用而不是时,出现了与…行关联的错误消息,导致崩溃。如果我继续执行,则每次执行线程1时它都会到达并位于线程1

  • 我还没有看到这个问题,这让我很惊讶。 以下内容不会编译: 然而,将此更改为强制转换对象并将其引用存储在条件语句之外的新对象中,可以解决此问题: 我的问题是,为什么Java中不允许这种行为?(特别是Java 5) 编辑:啊哈!谢谢大家。该死的现代IDE给出了模糊的错误消息。我已经开始打折了,这一次对我没有任何好处。(Netbeans警告我缺少括号和分号…)

  • 注意是8位类型(uint8_t),而无符号int是16位类型(uint16_t)。 以下并没有产生我所期望的结果。我希望它下溢,结果总是一个uint8_t,但它变成了一个有符号的int(int16_t)!!!为什么?