C ++模板class = typename

时间:2018-03-21 13:56:13

标签: c++ templates

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);

1 个答案:

答案 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 =的含义相同。在声明模板类型参数时,我们会使用classtypename

进行介绍
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中,可以进行类似的类比。编译器不会停止,因为在模板参数中需要未定义类型的地方会出现一些重载。它会尝试另一种重载。