【发布时间】:2019-03-06 16:54:00
【问题描述】:
假设我们有一个带有默认模板参数的类模板:
template <typename T = int>
class Foo {};
在函数内部创建变量时,我们可以省略尖括号:
int main()
{
Foo a; // gets properly deduced as Foo<int>
}
但我们不能对成员变量这样做:
struct S
{
Foo a; // Deduce Foo<int>
};
我们不能有这样的派生类型:
Foo* ptr; // Foo<int>*
Foo& ref; // Foo<int>&
int Foo::* mem_ptr; // int Foo<int>::*
std::function<Foo(const Foo&)> fn; // std::function<Foo<int>(const Foo<int>&)>
我们不能接受参数并返回它们:
Foo Bar(const Foo&); // Foo<int> (*)(const Foo<int>&)
为什么?这是否被认为是标准中的错误?有修复它的建议吗?省略尖括号有什么实际问题吗?
我的用例:
我有一个提供默认参数的类模板。模板参数是我自己从未使用过的专家专用功能,但它适用于那些想要完全灵活性的 1% 的专家。现在对于其他 99% 的人,我想隐藏 Foo 实际上是一个类模板但它不起作用,因为用户在声明它为成员变量时必须键入 Foo<>,当前的解决方案是:
template <typename T = int>
class BasicFoo {};
using Foo = BasicFoo<>;
但它使实现代码复杂化,一点也不优雅。
【问题讨论】:
-
@JesperJuhl:不,这是关于成员变量中的 CTAD 的问题。这是另一回事。
-
“但它使实现代码复杂化,一点也不优雅。”您认为在代码中的某个位置添加别名很复杂,但在所有位置添加语言规则并不复杂?
-
@SergeyA 像我这样的人认为这是一个错误并在 C++20 中修复了一些情况:open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0634r3.html
-
@Lyberta:“像我这样的人认为这是一个错误”不,他们没有。他们认识到可以改进的语言的一部分。 “错误”是语言中损坏的一部分。有区别。
标签: c++ templates language-lawyer c++17