天天看點

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

預設模闆,總是最後才會執行比對。

繼續閱讀