在模板函数中默认的模板要求空的尖括号 <>。

3

gcc 11.2无法编译此内容:

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<Test<>>(t);
}

这是一个编译器的bug吗?

这个问题似乎表明它应该有效。


顺便提一下,导致这种情况的实际用例有点更加复杂。我很快会添加一些详细信息。 - Radrich
3个回答

7
GCC是正确的。对于函数模板,允许省略空的模板参数列表<> ([temp.arg.explicit]/4)。在其他情况下,通常需要模板参数列表来命名特定的模板实例化,即使它是空的。请参见simple-template-id的语法,[temp.names]/1

作为规则的有限例外,如果类模板名称没有模板参数列表出现在需要具体类型的上下文中,那么它被称为“推导类类型的占位符”,这只允许在[dcl.type.class.deduct]中列出的特定上下文中使用。其中最常见的是变量声明,例如std::pair p("foo", 1),在C++17及更高版本中编译器将推导出std::pair<const char*,int>

在您的代码中,您尝试引用类模板Test的特定实例化,而没有指定模板参数列表,并且不是可以推断模板参数的上下文。因此,这是不允许的。


1

1
在你的第一段代码中,你将一个类模板(Test)指定为foo的模板参数,而不是类型(比如一个类模板实例)。你需要一个接受模板模板参数的函数来处理它。
例如:
#include <type_traits>

template<template<class> class T, class U> // T = Test, U = deduced to int
void foo(T<U>& bar) {
    std::cout << std::is_same<T<U>, Test<int>>::value << '\n'; // true
}

int main() {
    Test t;
    foo<Test>(t); // now ok
}

在您的第二个示例中,foo<Test<>>(t); 实例化了 foo<Test<int>>(Test<int>&),因为 <> 让模板实例化使用模板参数的默认类型,该默认类型是 int

1
这听起来很合理并且可行:https://godbolt.org/z/1vKf4x1Wr 但是使用foo<Test<long>>(t)时却不行:https://godbolt.org/z/1vKf4x1Wr 这让我感到惊讶和困惑。 - Radrich
@Radrich 如果你想让两个都起作用,你仍然需要使用带有“类型”的重载。示例 - Ted Lyngmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接