【问题标题】:Is it possible to deprecate implicit conversion while allowing explicit conversion?是否可以在允许显式转换的同时弃用隐式转换?
【发布时间】:2022-01-09 03:27:31
【问题描述】:

假设我有一个简单的Duration 类:

class Duration
{
    int seconds;
public:
    Duration(int t_seconds) : seconds(t_seconds) { }
};

int main()
{
    Duration t(30);
    t = 60;
}

我决定我不喜欢从int 隐式转换为Duration。我可以让构造函数explicit

class Duration
{
    int seconds;
public:
    explicit Duration(int t_seconds) : seconds(t_seconds) { }
};

int main()
{
    Duration t(30); // This is fine, conversion is explicit
    t = 60; // Doesn't compile: implicit conversion no longer present for operator=
}

但是如果我不想立即中断所有隐式转换为Duration 的调用代码怎么办?我想要的是这样的:

class Duration
{
    int seconds;
public:
    [[deprecated]]
    Duration(int t_seconds) : seconds(t_seconds) { }

    explicit Duration(int t_seconds) : seconds(t_seconds) { }
};

int main()
{
    Duration t(30); // Compiles, no warnings, uses explicit constructor
    t = 60; // Compiles but emits a deprecation warning because it uses implicit conversion
}

这将允许在识别当前依赖隐式转换的任何地方的同时编译现有代码,因此可以将它们重写为使用显式转换(如果它打算)或重写以具有正确的行为(如果不是)。

但是这是不可能的,因为我不能用Duration::Duration(int) 重载Duration::Duration(int)

除了“使转换显式,接受调用代码在您编写适当的更改之前不会编译”之外,有没有办法实现类似的效果?

【问题讨论】:

  • 是否可以为隐式转换打开编译器警告?以 gcc 中的-Wconversion 为例。
  • 在这种情况下,emit a warning 实际上并没有出现。不过,按照这些思路可能就足够了。
  • 你可以通过条件编译来做到这一点,#ifdef REFACTOR explicit Duration(int) #else Duration(int)。然后逐个项目编译并定义 REFACTOR(命令行)测试代码。完成所有项目后,删除 ifdef 和所有定义(或相反从所有项目上的定义开始并一个一个删除)

标签: c++ type-conversion


【解决方案1】:

您可以将Duration(int t_seconds) 转换为可以接受int 的模板函数并将其设置为已弃用。

#include<concepts>

class Duration {
  int seconds;
public:
  template<std::same_as<int> T>
  [[deprecated("uses implicit conversion")]]
  Duration(T t_seconds) : Duration(t_seconds) { }
  
  explicit Duration(int t_seconds) : seconds(t_seconds) { }
};

如果您允许t = 0.6,只需将same_as 更改为convertible_to

Demo.

【讨论】:

  • SFINAE 版本似乎不是that bad 一旦这给了我尝试的想法。好建议!
  • 降级到C++17C++11
  • @TheScore 将其用作constraint。就是说必须满足 std::same_as&lt;T, int&gt; 才能使 T 成为有效参数。
  • 注意,这个解决方案会破坏这样的代码:Duration minute() { return {60}; } 原因是在copy-list-initialization中,重载解析没有考虑explicitness,然后程序就生病了- 如果显式构造函数实际被选中,则形成。
  • 即使只是 template&lt;typename = void&gt; [[deprecated]] Duration(int t_seconds) : Duraction(t_seconds) {} 也可以,因为显式初始化总是会选择非模板的
猜你喜欢
  • 2017-03-08
  • 1970-01-01
  • 2020-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多