普通の型チェック
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
template <typename T> void func(T t) { static_assert(!std::is_pointer_v<T>, "T must not a pointer"); } int main() { func(1); // func(""); // error int a = 1; func(a); // func(&a); // error int* pa = &a; func(*pa); |
Tがポインタだとエラーになる。
variadicの場合
1 2 3 4 5 6 7 8 9 10 11 |
static void CheckKata(){} template<typename T, typename... ARGS> static void CheckKata(T firstArg, ARGS... args) { using NoConstT = typename std::add_pointer<std::remove_cv<std::remove_pointer<T>::type>::type>::type; static_assert( std::is_same_v<std::remove_cv_t<T>, wchar_t> || !std::is_same_v<NoConstT, wchar_t*>, "argument must not wchar_t*"); CheckKata(args...); } |
最初の引数の型Tに対してチェックしている。CheckKataに渡される引数がwchar_t*だったりポインタのポインタだったらエラーになる。ただwchar_tはセーフにしている。
remove_cvなどの挙動がいまいちよくわからないのでこの書き方であっているのか不明。以下のようなコードで実行時の型を表示してくれる。
1 2 3 4 5 |
std::cout << typeid(T).name() << '\n'; std::cout << typeid(std::decay_t<T>).name() << '\n'; std::cout << typeid(std::remove_cv_t<T>).name() << '\n'; std::cout << typeid(std::remove_const_t<T>).name() << '\n'; std::cout << typeid(std::remove_pointer_t<T>).name() << '\n'; |
is_sameは渡された2つの型が同じならtrue。
decayは配列参照などをポインタにしてくれる。
remove_cvはconstやvolatileを除去
remove_pointerはポインタを1つ除去する。
_vで終わるのはvalue,is_same::valueなどと同じ。
_tで終わるのはtype,remove_cv::typeなどと同じ。
ソース:https://github.com/ambiesoft/blogprogs/tree/master/6006/ConsoleApplication1