ChatGPT解决这个技术问题 Extra ChatGPT

模板默认参数

如果允许我执行以下操作:

template <typename T = int>
class Foo{
};

为什么我不允许在 main 中执行以下操作?

Foo me;

但我必须指定以下内容:

Foo<int> me;

C++11 引入了默认模板参数,现在我完全无法理解它们。


M
Michael Hoffmann

笔记:

从 C++17 开始,没有模板参数的 Foo me; 是合法的。请参阅此答案:https://stackoverflow.com/a/50970942/539997

适用于 C++17 之前的原始答案:

你所要做的:

Foo<> me;

模板参数必须存在,但您可以将它们留空。

可以将其想象为具有单个默认参数的函数 foo。表达式 foo 不会调用它,但 foo() 会。参数语法必须仍然存在。这与那是一致的。


@Pubby 我想如果 Foo might 是模板标识符或 might 是根据是否有默认参数的显式实例化,它会产生一些不必要的复杂性。更好地保留显式实例化语法。可以将其想象为具有单个默认参数的函数 foo。你不能像 foo 那样调用它,你用 foo() 来调用它。保持这种一致性是有意义的。
@sftrabbit 但你也不能调用没有像 foo 这样的参数的函数;但是,您可以将不带参数的类命名为 Foo
@aschepler 使用函数,模板参数可以从函数参数中推导出来。对于一个类,无法决定您是指具有默认参数的模板类还是非模板类。
@OlafDietsche 但您不能拥有同名的模板类和非模板类,因此编译器应该能够通过查看名称来决定。
@Pubby 我猜标准委员会也问过自己。现在,使用 C++17,在这种情况下不再需要 <>。查看我的答案以获取更多详细信息。
P
Paolo M

使用 C++17,您确实可以。

此功能称为 class template argument deduction,它为您声明模板化类型变量的方式增加了更多灵活性。

所以,

template <typename T = int>
class Foo{};

int main() {
    Foo f;
}

现在是 legal C++ code


奇怪的。刚刚在我的 C++17 项目中尝试过,但没有成功:“模板占位符类型 'const MyType' 必须后跟一个简单的 declarator-id”。我正在使用 GCC 7.3.0。
@Silicomancer 没有看到你的代码和命令行很难说......也许你正在处理指针like here
@PaoloM 哦很酷,很高兴知道它只是一个编译器版本问题。感谢您查看这个。
这应该是最佳答案 - 最佳答案已过时。
g
g24l

你不能这样做,但你可以这样做

typedef Foo<> Fooo;

然后做

Fooo me;

这与默认类型和:typedef Foo<float> Fooo;,没有默认类型有什么区别吗?
C++11-ish 的方式是说 using Fooo = Foo<>;
A
Andy Prowl

您可以使用以下内容:

Foo<> me;

并让 int 成为您的模板参数。尖括号是必须的,不能省略。


有道理,谢谢,但如下所述,为什么指定的类型不存在?
@user633658:您的意思是“类型说明符”吗?我不确定我是否理解
无论如何,关于需要空尖括号背后的原因,我只能做出猜测,它们都是为了排除单独使用模板名称可能产生的歧义,但我不得不承认我不知道确切的原因
我强烈怀疑对 <> 的要求是使编译器的解析器能够确定您指的是一个名为 foo 的模板类,而不是名为 foo 的其他东西。
R
Radrich

有点 不同的情况,但要晚一些,但涉及模板函数gcc 11.2 can't seem 编译:

template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
    Test t;
    foo<Test>(t);
}

但是has no problem with

template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
    Test t;
    foo<Test<>>(t);
}

当然

template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
    Test t;
    foo(t);
}

works - 但有时您需要明确强制类型。这是编译器错误吗?


请注意,这取决于编译器版本 - 您的第三个示例不适用于 C++14,但适用于 C++17。这似乎取决于 C++ 语言规范,而不是编译器错误。具体来说,如果您要部分指定模板(例如 foo<Test>(t)),您需要提供 <>对于每个默认模板 - 但是只需放置 foo(t) 就可以了。
答案提供了额外的信息,但它本身似乎是推测性的或部分是一个问题。
引发这个“有问题的答案”的实际用法需要模板参数。在这种情况下,它不是部分专业化。我认为这里的情况实际上是一样的——它是完全专业的。我相信这没有编译的另一个原因(但感谢您的评论)。
我提出了这个问题:stackoverflow.com/questions/71683140/…
如果您有新问题,请点击 Ask Question 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review
Y
Yogesh Aggarwal

根据 C++17 标准,必须传递模板参数。

但是,如果您仍然想要解决此问题,可以使用 using 关键字这样

template <typename T>
class Foo{
};
using IFoo=Foo<int>

或者,您也可以像这样使用 preprocessor

template <typename T>
class Foo{
};

#define IFoo Foo<int>

快速提醒

预处理器不利于调试。


这显然比 using IFoo=Foo<int> 更糟。宏的忽略命名空间