特化此函数模板时不能省略模板参数
Template arguments can't be omitted when specializing this function template
在 C++ 中,函数模板的显式特化如下:
template<typename T> return_type fun_name();
template<> return_type fun_name<int>(){/* blabla */}
上例中的<int>
称为模板参数。有时 <int>
可以省略,因为编译器可以做 Template Argument Deduction
但我无法找出为什么 Template Argument Deduction 在以下示例中失败:
//-------------failed case-------------
template <typename T>
struct deduce{
typedef T* type;
};
template <typename T>
typename deduce<T>::type fun1();
template <>
typename deduce<float>::type fun1<float>() //error if no "<float>" after fun1
{
}
//------------now the "Template Argument Deduction" works------------
template <typename T>
struct some_struct{
T* p;
};
template <typename T>
some_struct<T> fun2();
template <>
some_struct<float> fun2() // no error even if no "<float>" after fun2
{
}
如果fun1后没有<float>
,则报错信息为:
error: template-id ‘fun1<>’ for ‘float* fun1()’ does not match any template declaration
也许编译器认为typename
标记的类型(deduce<float>::type
)不如普通类型可靠?
Maybe the compiler think the type(deduce<float>::type
) marked by typename
is less reliable than normal types ?
和typename
没有任何关系,重点是deduce<T>::...
是nested-name-specifier;属于 Non-deduced contexts:
(强调我的)
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
所以,对于
template <>
typename deduce<float>::type fun1()
deduce<float>::type
(即float*
)将用于为deduce<T>::type
推导类型T
,但不会推导T
,模板参数推演失败。您必须将其明确指定为 float
.
让我举例说明为什么非推导上下文是非推导的。模板推导基本上是在尝试匹配输入。如果我有:
template <class T> void foo(T );
我打电话给foo(4)
,这很简单。 T=int
。如果我调用 foo('x')
,T=char
。这些很容易替换。如果 T
嵌套在类型中的某处,例如:
template <class T> void bar(std::vector<T> );
这仍然是完全可行的。如果我用 std::vector<std::vector<float>>
、T=std::vector<float>
调用它。还是没问题。
现在考虑这个:
template <class T> void baz(typename X<T>::type );
baz(4);
什么是 T
?在我们之前的所有案例中,T
有一个明显的选择,它是直接从传递给函数模板的参数中推导出来的。但在这里,情况并非如此。我们有一个额外的间接层——我们需要推导一个 T
来创建一个类型 X<T>
,其成员 typedef type
是 int
。我们如何找到这样的东西?
现在假设我们有这个:
template <class T> struct X { using type = T; };
好了,现在很简单了吧? T=int
?好吧,没那么快。对于主模板,在这种情况下会起作用。但是,如果还有这种专业化怎么办:
template <class T> struct X<T*> { using type = T; };
(即 X
为 std::remove_pointer
)。现在我们处于 T=int
有效的情况......但 T=int*
也有效。也许还有一些其他类型也适用于 int
。如何选择合适的?
这个问题 - 在 qualified-id 的嵌套名称说明符中选择模板参数 - 真的很难,没有明显的前进方向。所以编译器不会采取前进的道路。这是一个非推导的上下文。 T
永远不会在对 baz
的调用中推导出来,调用者必须提供它:
baz<int>(4); // ahhhhh, ok, you wanted X<int>::type
回到你的问题。 some_struct<T>
是推导上下文,但 typename deduce<T>::type
是非推导上下文。我希望现在很清楚为什么前者有效而后者无效。
在 C++ 中,函数模板的显式特化如下:
template<typename T> return_type fun_name();
template<> return_type fun_name<int>(){/* blabla */}
上例中的<int>
称为模板参数。有时 <int>
可以省略,因为编译器可以做 Template Argument Deduction
但我无法找出为什么 Template Argument Deduction 在以下示例中失败:
//-------------failed case-------------
template <typename T>
struct deduce{
typedef T* type;
};
template <typename T>
typename deduce<T>::type fun1();
template <>
typename deduce<float>::type fun1<float>() //error if no "<float>" after fun1
{
}
//------------now the "Template Argument Deduction" works------------
template <typename T>
struct some_struct{
T* p;
};
template <typename T>
some_struct<T> fun2();
template <>
some_struct<float> fun2() // no error even if no "<float>" after fun2
{
}
如果fun1后没有<float>
,则报错信息为:
error: template-id ‘fun1<>’ for ‘float* fun1()’ does not match any template declaration
也许编译器认为typename
标记的类型(deduce<float>::type
)不如普通类型可靠?
Maybe the compiler think the type(
deduce<float>::type
) marked bytypename
is less reliable than normal types ?
和typename
没有任何关系,重点是deduce<T>::...
是nested-name-specifier;属于 Non-deduced contexts:
(强调我的)
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
1) The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
所以,对于
template <>
typename deduce<float>::type fun1()
deduce<float>::type
(即float*
)将用于为deduce<T>::type
推导类型T
,但不会推导T
,模板参数推演失败。您必须将其明确指定为 float
.
让我举例说明为什么非推导上下文是非推导的。模板推导基本上是在尝试匹配输入。如果我有:
template <class T> void foo(T );
我打电话给foo(4)
,这很简单。 T=int
。如果我调用 foo('x')
,T=char
。这些很容易替换。如果 T
嵌套在类型中的某处,例如:
template <class T> void bar(std::vector<T> );
这仍然是完全可行的。如果我用 std::vector<std::vector<float>>
、T=std::vector<float>
调用它。还是没问题。
现在考虑这个:
template <class T> void baz(typename X<T>::type );
baz(4);
什么是 T
?在我们之前的所有案例中,T
有一个明显的选择,它是直接从传递给函数模板的参数中推导出来的。但在这里,情况并非如此。我们有一个额外的间接层——我们需要推导一个 T
来创建一个类型 X<T>
,其成员 typedef type
是 int
。我们如何找到这样的东西?
现在假设我们有这个:
template <class T> struct X { using type = T; };
好了,现在很简单了吧? T=int
?好吧,没那么快。对于主模板,在这种情况下会起作用。但是,如果还有这种专业化怎么办:
template <class T> struct X<T*> { using type = T; };
(即 X
为 std::remove_pointer
)。现在我们处于 T=int
有效的情况......但 T=int*
也有效。也许还有一些其他类型也适用于 int
。如何选择合适的?
这个问题 - 在 qualified-id 的嵌套名称说明符中选择模板参数 - 真的很难,没有明显的前进方向。所以编译器不会采取前进的道路。这是一个非推导的上下文。 T
永远不会在对 baz
的调用中推导出来,调用者必须提供它:
baz<int>(4); // ahhhhh, ok, you wanted X<int>::type
回到你的问题。 some_struct<T>
是推导上下文,但 typename deduce<T>::type
是非推导上下文。我希望现在很清楚为什么前者有效而后者无效。