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

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

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

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

Q&A

解決済

1回答

1768閲覧

SFINAE の書き方(非型の選別)について

jbe00214

総合スコア63

C++

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

1グッド

0クリップ

投稿2021/04/19 00:30

前提・実現したいこと

型特性関数とenable_if_tを使って,メンバ関数のオーバーロード解決はできるのですが,非型の場合にうまくいきません。具体的には,クラステンプレート仮引数の値によって,クラスメンバ関数のオーバーロード解決を行いたいというものです。次のコード例のように,型 T をenable_ifの条件にする場合は成功するのですが,size_tの場合には,エラーが出ます。
どこの点に問題があるのでしょうか。ご教示いただける方がおられれば教えてください。

発生している問題・エラーメッセージ

No type named 'type' in 'std::__1::enable_if<false, nullptr_t>'; 'enable_if' cannot be used to disable this declaration

該当のソースコード

C++

1using namespace std; 2template<size_t N> 3struct Foo{ 4 /* うまくいく例 5 template<typename T,enable_if_t<is_same_v<T,int>,std::nullptr_t> =nullptr> 6 array<T,1> 7 func(){array<T,1> a;return a;} 8 9 template<typename T,enable_if_t<!is_same_v<T,int>,std::nullptr_t> =nullptr> 10 array<T,N> 11 func(){array<T,N>a;return a;} 12 */ 13 14 template<typename T,enable_if_t<(N==1),std::nullptr_t> =nullptr> 15 array<T,1> 16 func(){array<T,1> a;return a;} 17 18 template<typename T,enable_if_t<(N>1),std::nullptr_t> =nullptr> 19 array<T,N> 20 func(){array<T,N>a;return a;} 21 22}; 23 24int main() 25{ 26 Foo<1> f; 27 28 array<int,1> ar = f.func<int>(); 29} 30

試したこと

上記の成功例のとおり。enable_if_tの第一引数はboolなのでTの比較の場合とNの比較の両者ともに真偽の判断という意味では同じだと思っています。

補足情報(FW/ツールのバージョンなど)

clang
C++17

ttact👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

値 (型) がいつ解決するかが違います。

Tint と比較する例では Tfunc を呼出すときに解決しますが、 NFoo<1> のときに解決しようとして展開に失敗するので (func<int> ではなく) Foo<1> 全体の失敗として解釈されてしまいます。

この場合は型か非型の問題ではないです。

修正方法

修正する方法は状況によって色々と考えられますが、設計をあまり変えないようにという前提であれば Foo の型引数の T を無駄に受け取るようなテンプレートを挟めばよいです。 これによって T が確定するまで func が展開されませんので func を呼出すときに func の解決 (SFINAE) が試みられるため、 Foo 自体の展開には失敗しません。

cpp

1#include <iostream> 2#include <array> 3#include <type_traits> 4 5template<class T> 6class always_true : public std::true_type { 7}; 8 9template<std::size_t N> 10struct Foo{ 11 template<typename T, typename std::enable_if<(N==1) && always_true<T>::value, std::nullptr_t>::type =nullptr> 12 std::array<T,1> 13 func(void){std::array<T,1> a; return a;} 14 15 template<typename T, typename std::enable_if<(N>1) && always_true<T>::value, std::nullptr_t>::type =nullptr> 16 std::array<T,N> 17 func(void){std::array<T,N> a; return a;} 18}; 19 20int main(void) 21{ 22 Foo<(size_t)1> f; 23 std::array<int,1> ar = f.func<int>(); 24}

投稿2021/04/19 02:33

編集2021/04/19 04:04
SaitoAtsushi

総合スコア5714

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

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

jbe00214

2021/04/19 03:33

いつもありがとうございます。ご説明はわかったようなわからないような。どのルールに合致していないのかがよく理解できません。どのように修正すると良いのか教えていただけますか。
jbe00214

2021/04/19 05:13

素晴らしい。ありがとうございます。解決できて感謝しています。true_type::valueを直接記述してもだめかと思ってやってみたら,やっぱりだめでした。おそらく同じ理由なのだと思います。今回の問題は,何が悪いのかの理解が追いついていていないので,後学のためにも,別途文献等を読んでみたいと思いますが,今回の問題は,言語上どういったルールに反しているのか,キーワードでも参考webのurlでも結構ですので教えていただけませんでしょうか。
SaitoAtsushi

2021/04/19 07:07

・ 実引数と仮引数のマッチに失敗 (エラー発生) する ・ 展開した結果にエラーが含まれる というのは別物です。 enable_if に偽値が与えられればエラーを発生させるので本来的にエラーなのですが、マッチを試す段階でのエラーは「候補からの除外」にとどめられるため全体としてはすぐさまエラーになるわけではないというのが SFINAE のルールです。 ですから SFINAE の状況にないときに enable_if に偽値が与えられればエラーなのです。 質問の事例では Foo<1> f; と書いた段階で 1 は N にマッチし、この時点ですでに enable_if も解決してしまうので func についてマッチを試すという状況になく、単に Foo を展開した結果にエラーが含まれる (エラーになる func の定義がある) のでエラーということになってしまいます。 テンプレートの名前解決は Two-phase name lookup というルールに従います。 テンプレート中において名前が何を意味するのか解決できるものは解決し、解決できないものは解決できるまで後回しという二段階です。 私が提案した修正方法は実際には利用しない T への依存を作ることで「解決できるまで後回し」のほうにあてはまるようにしているのです。 これによって Foo<1> の段階では処理されず、 T が何者か分かったとき (func の呼出しのとき) になってから処理されるので SFINAE のルールで処理されることになります。
jbe00214

2021/04/19 07:39

ありがとうございます。テンプレートはとても難しく,教科書は読んでいるので,ご説明の中の所々は聞いたことがある事項もありましたが,断片的な理解でしかありませんでした。たいへんご丁寧な説明だったので,私の中途半端な理解が進みました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問