【发布时间】:2021-11-19 08:12:16
【问题描述】:
如果我有一个广泛使用的名为 Foo 的类模板,我想将其重命名为 Bar 而不必以原子方式更新其所有用户,那么在 C++17 之前我可以简单地使用类型别名:
template <typename T>
class Bar {
public:
// Create a Bar from a T value.
explicit Bar(T value);
};
// An older name for this class, for compatibility with callers that haven't
// yet been updated.
template <typename T>
using Foo = Bar<T>;
在大型分布式代码库中工作时,这非常有用。然而,从 C++17 开始,这似乎被类模板参数推导指南所打破。例如,如果此行存在:
template <typename T>
explicit Foo(T) -> Foo<T>;
那么在重命名类时,显而易见的事情就是将演绎指南中的Foos 更改为Bars:
template <typename T>
explicit Bar(T) -> Bar<T>;
但现在随机调用者中的表达式Foo(17) 曾经是合法的,但现在是错误的:
test.cc:42:21: error: alias template 'Foo' requires template arguments; argument deduction only allowed for class templates
static_cast<void>(Foo(17));
^
test.cc:34:1: note: template is declared here
using Foo = Bar<T>;
^
有没有什么简单和通用的方法可以以完全兼容的方式给一个具有演绎指导的类提供两个同时命名的名称?我能想到的最好的方法是在两个名称下定义该类的公共 API 两次,使用转换运算符,但这远非简单和通用。
【问题讨论】:
-
如果您从新类派生旧类,您将免费获得一些转换。但是,如果您的 API 用户混合了
auto&和Foo&,则没有完美的解决方案,这在旧代码库中是很有可能的。