template <class = typename T::type>
是什么意思?你能引用我的博客,说明这个吗?
这个问题最初来自对sfinae on cpp reference
的解释template <typename A>
struct B { typedef typename A::type type; };
template <
class T,
class = typename T::type, // SFINAE failure if T has no member type
class U = typename B<T>::type // hard error if T has no member type
// (guaranteed to not occur as of C++14)
> void foo (int);
答案 0 :(得分:7)
首先,我将解释typename T::type
。这只是成员类型的访问。以下是访问成员类型的示例:
struct foo {
using bar = int;
};
int main() {
foo::bar var{};
// var has type int
}
为什么typename
?它只是意味着我们想要访问一个类型。由于我们在模板中,T
是未知类型,foo::bar
也可能意味着访问静态变量。为了消除歧义,我们表示我们有效地希望通过明确键入typename
来访问类型。
好的,现在class =
意味着什么?
class =
与typename =
的含义相同。在声明模板类型参数时,我们会使用class
或typename
:
template<typename A, typename B>
struct baz {};
但是作为C ++中的任何参数,名称是可选的。我本可以写这个,以下是完全等同的:
template<typename, typename>
struct baz {};
另外,您知道在函数参数中,我们可以指定默认值吗?像那样:
void func(int a, int b = 42);
int main () {
func(10); // parameter b value is 42
// We are using default value
}
我们也可以省略参数名称:
void func(int, int = 42);
就像函数参数一样,模板参数可以省略它的名称,并且可以有一个默认值。
template<typename, typename = float>
struct baz {};
baz<int> b; // second parameter is float
现在我们有了这个声明:
template <
class T,
class = typename T::type, // SFINAE failure if T has no member type
class U = typename B<T>::type // hard error if T has no member type
// (guaranteed to not occur as of C++14)
> void foo (int);
这里我们声明一个以int作为参数的函数,并且有三个模板参数。
第一个参数是一个简单的命名参数。名称为T
,它是一个类型模板参数。第二个也是类型参数,但它没有名称。但是,它的默认值为T::type
,其成员类型为T
。我们通过指定T::type
明确告诉编译器T
必须是typename
的成员类型。第三个参数类似于第二个参数。
这是SFINAE开始使用的地方:当使用默认参数时,T::type
作为成员类型不存在,如何将第二个模板参数分配给它?我们不能。如果T::type
不存在,我们就无法分配第二个模板参数。但是编译器只是尝试另一个函数,而不是使它成为错误,因为有可能另一个函数可以调用。
这与简单重载非常相似。您拥有f
功能。它需要一个float
参数,另一个需要std::string
的重载。想象一下,你打电话给f(9.4f)
。编译器是否因为std::string
无法构造float
而窒息?没有!编译器不是傻瓜。它会尝试另一个重载,并找到float
版本并调用它。在SFINAE中,可以进行类似的类比。编译器不会停止,因为在模板参数中需要未定义类型的地方会出现一些重载。它会尝试另一种重载。