C ++模板类=类型名

cav*_*ger 5 c++ templates

什么template <class = typename T::type>意思 您能否介绍我一些描述此规范的博客?

这个问题最初来自于对CPP参考Sfinae的解释

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);
Run Code Online (Sandbox Code Playgroud)

Gui*_*cot 11

首先,我将说明typename T::type。这只是成员类型的访问。这是访问成员类型的示例:

struct foo {
    using bar = int;
};

int main() {
    foo::bar var{};

    // var has type int
}
Run Code Online (Sandbox Code Playgroud)

那么为什么typename呢?这只是意味着我们要访问类型。由于我们在模板中并且T是未知类型,foo::bar因此也可能意味着访问静态变量。为了消除歧义,我们表示我们实际上想通过显式键入来访问类型typename

好的,现在class =意味着什么?

class =意味着同样的事情typename =。在声明模板类型参数时,我们使用class或进行介绍typename

template<typename A, typename B>
struct baz {};
Run Code Online (Sandbox Code Playgroud)

但是作为C ++中的任何参数,名称都是可选的。我可以写这篇文章,而以下内容完全等效:

template<typename, typename>
struct baz {};
Run Code Online (Sandbox Code Playgroud)

另外,您知道函数参数中是否可以指定默认值?像那样:

void func(int a, int b = 42);

int main () {
    func(10); // parameter b value is 42
              // We are using default value
}
Run Code Online (Sandbox Code Playgroud)

我们还可以省略参数名称:

void func(int, int = 42);
Run Code Online (Sandbox Code Playgroud)

就像函数参数一样,模板参数可以省略其名称,并且可以具有默认值。

template<typename, typename = float>
struct baz {};

baz<int> b; // second parameter is float
Run Code Online (Sandbox Code Playgroud)

放在一起

现在我们有了这个声明:

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);
Run Code Online (Sandbox Code Playgroud)

在这里,我们声明一个函数,该函数以int作为参数,并具有三个模板参数。

第一个参数是一个简单的命名参数。名称是T并且它是类型模板参数。第二个也是类型参数,但是没有名称。但是,其默认值为T::type,这是的成员类型T。我们通过指定明确告诉编译器T::type必须是的成员类型。第三个参数与第二个相似。Ttypename

这就是SFINAE的作用:使用默认参数,但T::type由于不存在成员类型时,如何为该模板分配第二个模板参数?我们不能。如果T::type不存在,则无法分配第二个模板参数。但是编译器不会出错,而只是尝试另一个函数,因为可能会调用另一个函数。

这与简单的重载非常相似。你有 f功能。它带一个float参数,另一个带的重载std::string。想象你打电话f(9.4f)。编译器会因为a std::string不可从a构造而阻塞float吗?没有!编译器并不愚蠢。它将尝试另一个重载,并找到float版本并调用它。在SFINAE中可以做出类似的比喻。编译器不会停止,因为某些地方需要在模板参数中使用未定义类型的重载。它将尝试另一个过载。