如何使用推导指南为 C++ 类模板提供两个兼容的名称?

jac*_*bsa 3 c++ c++17 ctad

如果我有一个广泛使用的类模板,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>;
Run Code Online (Sandbox Code Playgroud)

当在大型分布式代码库中工作时,这非常有用。然而,从 C++17 开始,类模板参数推导指南似乎打破了这一点。例如,如果存在这一行:

template <typename T>
explicit Foo(T) -> Foo<T>;
Run Code Online (Sandbox Code Playgroud)

那么重命名类时显而易见的事情就是将Foo推导指南中的 s 更改为Bars:

template <typename T>
explicit Bar(T) -> Bar<T>;
Run Code Online (Sandbox Code Playgroud)

但现在随机调用者中的表达式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>;
^
Run Code Online (Sandbox Code Playgroud)

是否有任何简单且通用的方法可以以完全兼容的方式为带有推导指南的类提供两个同时名称?我能想到的最好的办法是用两个名称定义类的公共 API 两次,并使用转换运算符,但这远非简单和通用。

康桓瑋*_*康桓瑋 5

你的问题正是P1814R0: Wording for Class Template Argument Deduction for Alias Templates 想要解决的问题,也就是说,在C++20中,你只需要添加推导指南即可Bar使以下程序格式良好:

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>;

template <typename T>
explicit Bar(T) -> Bar<T>;

int main() {
  Bar bar(42);
  Foo foo(42); // well-formed
}
Run Code Online (Sandbox Code Playgroud)

演示。

但由于是C++20的特性,目前C++17中还没有解决方案。