質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

704閲覧

可変長コンテナの使い方

__ook

総合スコア49

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/03/16 09:21

以下の記事を読み、
https://qiita.com/negi-drums/items/3c841dca517a2bc99f07

可変長コンテナ部を理解しようと動かしていました。

cpp

1#include <iostream> 2#include <type_traits> 3#include <typeinfo> 4#include <tuple> 5 6// なぜこれがないと 7// template<template<int...> class Vec, int Head, int... Tail>は 8// エラーになるのか。 9template<template<int...> class, int...> struct remove_zero; 10 11/* 12template<template<int...> class Vec, int Head, int... Tail> 13struct remove_zero<Vec, Head, Tail...> { 14 15 template<int... Args> using vec = std::conditional_t<Head == 0, Vec<Args...>, Vec<Head, Args...>>; 16 17 using type = typename remove_zero<vec, Tail...>::type; // なんのためにある? 18}; 19*/ 20 21template<template<int...> class Vec, int Head, int... Tail> 22struct remove_zero<Vec, Head, Tail...> { 23 template<int... Args> using vec = Vec<Args...>; 24}; 25 26/* 27// なんのためにある? 28template<template<int...> class Vec> 29struct remove_zero<Vec> { 30 using type = Vec<>; 31}; 32*/ 33 34template<int...> 35struct S; 36 37int main() { 38 std::cout << typeid(remove_zero<S, 1, 0, 2, 0, 3>).name() << std::endl; 39}

以上のコードのArgsには何が渡るのでしょうか。
また、template<template<int...> class, int...> struct remove_zero;をなくすとなぜエラーになるのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

type はまさに結果の型の定義ですから必要です。 remove_zero<S, 1, 0, 2, 0, 3>::typeS<1,2,3> になるというのがそのクラスの挙動です。

remove_zero は再帰しながら 0 を排除した型引数を蓄積するので Args には最終的には 1,2,3 が渡ります。 再帰の途中では 1, 1,2, 1,2,3 という段階を踏んで蓄積されます。

テンプレートの特殊化はその名が示す通り特殊な場合について定義するものです。 特殊でない場合が定義されていないと特殊化は出来ません。 特殊化によって「少なくとも 1 個以上の整数が型引数として渡されている場合」のテンプレートが引数を減らしながら再帰し、最終的には「引数がゼロ個しかない場合」のテンプレートの type が順繰りにそれを実体化したテンプレートの type として連鎖的に定義されるわけです。

投稿2020/03/16 10:44

SaitoAtsushi

総合スコア5684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

__ook

2020/03/17 00:17

ArgsにはTailが入るのでしょうか…? あと再帰が無限ループするような気がして…しないので僕が間違っているのはわかるのですが… 0がない場合、Vec<Head, Args...>がなぜ渡され続けないのでしょうか。
SaitoAtsushi

2020/03/17 01:42

Args に Tail が入るのかというのは、間接的にはそうなるかもしれませんが Head を蓄積しているという方がより実際の考え方に近いと思います。 それは書いてある通りだとしか言えないので処理を理解してもらうしか仕方がないのですが……。 ここではクラスもテンプレートですし、その中にエイリアステンプレートがあるという二重のテンプレートなのがややこしいですね。 Head はクラステンプレートの型引数で Args はエイリアステンプレートの型引数であるというのを意識して読んでみるといいかもしれません。
__ook

2020/03/17 02:06

すみません、本当理解が遅く… Head = 0の場合、Argsには何も入らない。0以外の場合、HeadがVecの型として追加される。 その後のremove_zero<vec, Tail...>::typeで再帰し繰り返される、というイメージをしています。 が、その考えだと template<template<int...> class Vec, int Head, int... Tail> struct remove_zero<Vec, Head, Tail...> { using vec = std::conditional_t<Head == 0, Vec<>, Vec<Head>>; using type = typename remove_zero<vec, Tail...>::type; }; これでできるのかな、とも思ったのですがエラーになりました。 これはただの構文ミスで考えはあっていますか?
SaitoAtsushi

2020/03/17 02:31

何を考えているのか私には読み取れませんが、構文上の問題ではないと思います。 最初の呼び出しでは Vec は S であるということを思い出してください。 Vec<Head> は S<1> のことです。 それを次の remove_zero に渡して何ができるというというのでしょう? (Vec はテンプレートでなければならないので型を渡せませんが。)
__ook

2020/03/17 03:10

ああ…理解できました、Argsは蓄積されたSの数字ですね…ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問