天天看点

std::nullptr_t & std::void_tstd::nullptr_tstd::void_t

std::nullptr_t

std::nullptr_t

nullptr

的模板类型,用法如下:

#include <iostream>
#include <type_traits>

void foo(int *) {
    std::cout << "int*\n";
}

void foo(double *) {
    std::cout << "double*\n";
}

void foo(std::nullptr_t) {
    std::cout << "nullptr\n";
}


int main() {
    int *a = nullptr;
    double *b = nullptr;
    foo(a);
    foo(b);
    foo(nullptr);  // (1)
    return 0;
}
/*
int*
double*
nullptr
*/
           

(1)中,如果没有

std::nullptr_t

nullptr

不知道应该匹配

int*

还是

double*

std::void_t

该模板的定义如下:

template< class... >
using void_t = void;
           

看起来没啥卵用,这个需要和SFINAE结合使用。举个例子,判定传入的结构是否包含

tp

类型:

#include <iostream>
#include <utility>

// 泛型模板
template<typename T, typename = void>
struct HasTypeFoo : std::false_type {
};

// 模板特化,T::tp 特化的模板
template<typename T>
struct HasTypeFoo<T, std::void_t<typename T::tp>> : std::true_type {
};

struct Foo {
    using tp = int;
};

struct FooFake {
    using tp1 = double;
};

struct SubFoo : Foo {
    using tp2 = float;
};

int main() {
    std::cout << HasTypeFoo<Foo>::value << std::endl;
    std::cout << HasTypeFoo<FooFake>::value << std::endl;
    std::cout << HasTypeFoo<SubFoo>::value << std::endl;
    return 0;
}
           

上面的代码中,

HasTypeFoo

是泛型模板。如果泛型

T

tp

类型成员,那么会特化成

std::void_t

类型;否则匹配失败,SFINAE 规则会自动匹配

typename = void

的候选类型。

这里的代码中,

std::void_t

的左右就是为了模板特化。因为

typename = void

默认模板,总是最后才会执行匹配。

继续阅读