🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C++

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

Q&A

解決済

1回答

658閲覧

SFINAE が効かない.....??

yoshiki_iwasa

総合スコア23

C++

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

0グッド

0クリップ

投稿2021/03/02 10:01

#質問概要
SFINAEを使って、テンプレートクラスのメンバ関数のオーバーロードの適用を分岐させようとしています。
しかし、SFINAEが効いて欲しいところでなぜか効いてくれず、コンパイルエラーになってしまいます....

#質問詳細
※ 各クラス・構造体はft名前空間に定義しています。

SFINAEのための構造体を以下のように定義しています。

C++

1 template <bool B, typename T> 2 class enable_if 3 { 4 public: 5 typedef T type; 6 }; 7 8 9 template <typename T> 10 class enable_if<false, T> 11 {}; 12 13 template <typename T, typename U> 14 struct is_same 15 { 16 static const bool value = false; 17 }; 18 19 template <typename T> 20 struct is_same <T, T> 21 { 22 static const bool value = true; 23 }; 24 25 template <class Iterator> 26 struct iterator_traits 27 { 28 29 typedef typename Iterator::value_type value_type; 30 typedef typename Iterator::difference_type difference_type; 31 typedef typename Iterator::pointer pointer; 32 typedef typename Iterator::reference reference; 33 typedef typename Iterator::iterator_category iterator_category; 34 }; 35

これらのSFINAEを使って、以下ように関数のオーバーロードをしようとしています。

C++

1 2template <class T> 3 class list 4 { 5 ~~~~~~~~~~~~~~~~~~ 6 /*Iterator assign*/ 7 8 template <class InputIterator> \ 9 void assign( 10 typename ft::enable_if<ft::is_same<typename ft::iterator_traits<InputIterator>::value_type, value_type>::value, InputIterator>::type first, 11 InputIterator last); 12 13 /*Fill assign*/ 14 void assign(size_type n, const value_type& val); 15 ~~~~~~~~~~~~~~~~~~~ 16 17} 18 19 20int main() 21{ 22 ft::list<int> lst; 23 lst.assign((size_t)5, 42); 24}

上記のようにmain 関数を書いてコンパイルします。

% g++ -std=c++98 main.cpp

##所望の挙動

まず、Iterator assign がコンパイル可能か見に行って、今回はtypedef typename Iterator::value_type value_type;が定義できないことから、ここでSFINAEが効いて Fill assign を見にいくことでコンパイル成功となって欲しいです。

##実際の挙動
しかし、結果は、以下のようなエラー文が出て、コンパイル失敗してしまいます。

./../SFINAE.hpp:39:20: error: type 'int' cannot be used prior to '::' because it has no members typedef typename Iterator::value_type value_type; ^ ./list.hpp:167:51: note: in instantiation of template class 'ft::iterator_traits<int>' requested here typename ft::enable_if<ft::is_same<typename ft::iterator_traits<InputIterator>::value_type, value_type>::value, InputIterator>::type first, ^ main.cpp:39:9: note: while substituting deduced template arguments into function template 'assign' [with InputIterator = int] lst.assign((size_t)5, 42);

要は、 Iterator assign がコンパイルできない段階でなぜかコンパイルエラー確定になってしまっているんです。
どうして、SFINAMEの機能が効かないのでしょうか...
調べても結論が出ませんでしたので質問させていただきます。よろしくお願いします。

#listクラス全体

もし必要だったら....

C++

1namespace ft 2{ 3 template <class T> 4 class list 5 { 6 class list_const_iterator; 7 class node 8 { 9 public: 10 node* right; 11 node* left; 12 T *data; 13 14 node() : right(this), left(this), data(NULL) {return ;}; 15 node(node *f, node* b, T d): right(f), left(b), data(new T(d)){ return ;}; 16 node(const T& val) : data(new T(val)){}; 17 void operator=(node x) 18 { 19 this->data = x.data; 20 this->left = x.left; 21 this->right = x.right; 22 } 23 }; 24 25 class list_iterator 26 { 27 public: 28 friend class list_const_iterator; 29 typedef T value_type; 30 typedef ptrdiff_t difference_type; 31 typedef T* pointer; 32 typedef T& reference; 33 typedef std::iterator<std::bidirectional_iterator_tag, T> iterator_category; 34 35 36 node _node; 37 list_iterator(){}; 38 list_iterator(const node& other) : _node(other){}; 39 list_iterator(list_const_iterator other) : _node(other._node){}; 40 ~list_iterator(){}; 41 42 reference operator*(); 43 pointer operator->(); 44 list_iterator &operator++(); 45 list_iterator operator++(int); 46 list_iterator &operator--(); 47 list_iterator operator--(int); 48 bool operator==(const list_iterator &other) const; 49 bool operator!=(const list_iterator &other) const; 50 51 list_iterator operator=(const list_iterator &other) 52 { 53 this->_node = other._node; 54 return (*this); 55 } 56 57 }; 58 59 class list_const_iterator 60 { 61 62 public: 63 friend class list_iterator; 64 typedef T value_type; 65 typedef ptrdiff_t difference_type; 66 typedef const T* pointer; 67 typedef const T& reference; 68 typedef std::bidirectional_iterator_tag iterator_category; 69 70 71 node _node; 72 list_const_iterator(){}; 73 list_const_iterator(const node& other) : _node(other){}; 74 list_const_iterator(const list_iterator& other) : _node(other._node) {} 75 ~list_const_iterator(){}; 76 77 78 reference operator*(); 79 pointer operator->(); 80 list_const_iterator &operator++(); 81 list_const_iterator operator++(int); 82 list_const_iterator &operator--(); 83 list_const_iterator operator--(int); 84 85 86 bool operator==(const list_const_iterator &other) const; 87 bool operator!=(const list_const_iterator &other) const; 88 }; 89 90 91 public: 92 typedef T value_type; 93 typedef allocator<T> Allocator; 94 typedef Allocator allocator_type; 95 typedef typename allocator_type::reference reference; 96 typedef typename allocator_type::const_reference const_reference; 97 typedef typename allocator_type::pointer pointer; 98 typedef typename allocator_type::const_pointer const_pointer; 99 typedef typename allocator_type::size_type size_type; 100 typedef list_iterator iterator; 101 typedef list_const_iterator const_iterator; 102 typedef ft::l_reverse_iterator<iterator> reverse_iterator; 103 typedef ft::l_reverse_iterator<const_iterator> const_reverse_iterator; 104 typedef ptrdiff_t difference_type; 105 106 /* 107 Constructor 108 */ 109 explicit list (const allocator_type& alloc = allocator_type()); 110 explicit list (size_type n, const value_type& val = value_type(), 111 const allocator_type& alloc = allocator_type()); 112 113 template <class InputIterator> 114 list ( 115 typename ft::enable_if<ft::is_same<typename ft::iterator_traits<InputIterator>::value_type, typename off_const<value_type>::value_type>::value, InputIterator>::type first, 116 InputIterator last, 117 const allocator_type& alloc = allocator_type()); 118 list (const list& x); 119 120 /* 121 Destructor 122 */ 123 ~list(){}; 124 125 /* 126 Iterators 127 */ 128 iterator begin(); 129 const_iterator begin() const; 130 iterator end(); 131 const_iterator end() const; 132 reverse_iterator rbegin(); 133 const_reverse_iterator rbegin() const; 134 reverse_iterator rend(); 135 const_reverse_iterator rend() const; 136 /* 137 Capacity 138 */ 139 size_type size() const; 140 bool empty() const; 141 size_type max_size() const; 142 /* 143 Element access 144 */ 145 reference front(); 146 const_reference front() const; 147 reference back(); 148 const_reference back() const; 149 /* 150 Modifiers 151 */ 152 153 154 template <class InputIterator> \ 155 void assign( 156 typename ft::enable_if<ft::is_same<typename ft::iterator_traits<InputIterator>::value_type, value_type>::value, InputIterator>::type first, 157 InputIterator last); 158 void assign(size_type n, const value_type& val); 159 160 iterator insert(iterator position, const value_type& val); 161 void insert(iterator position, size_type n, const value_type& val); 162 template<class InputIterator> 163 void insert( 164 iterator position, 165 typename ft::enable_if<ft::is_same<typename ft::iterator_traits<InputIterator>::value_type, value_type>::value, InputIterator>::type first, 166 InputIterator last); 167 168 169 iterator erase(iterator position); 170 iterator erase(iterator first, iterator last); 171 172 void push_back(const value_type& val); 173 void pop_back(); 174 void push_front(const value_type& val); 175 void pop_front(); 176 void swap(list &x); 177 void resize (size_type n, value_type val = value_type()); 178 void clear(); 179 180 /* 181 Operations 182 */ 183 184 void splice (iterator position, list& x); 185 void splice (iterator position, list& x, iterator i); 186 void splice (iterator position, list& x, iterator first, iterator last); 187 void remove (const value_type& val); 188 template <class Predicate> 189 void remove_if (Predicate pred); 190 void unique(); 191 template <class BinaryPredicate> 192 void unique (BinaryPredicate binary_pred); 193 194 void merge (list& x); 195 template <class Compare> 196 void merge (list& x, Compare comp); 197 void sort(); 198 template <class Compare> 199 void sort(Compare comp); 200 201 private: 202 node* _list; //head 203 size_type _size; 204 /* 205 Private Functions 206 */ 207 void make_sequence(typename list<T>::node *, typename list<T>::node *); 208 209 210 }; 211 212 213} // namespace ft 214

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

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

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

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

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

yohhoy

2021/03/03 08:06

GCCオプションに -std=c++98 を指定されていますが、C++98準拠は要件ですか?(C++11も使えない?)
guest

回答1

0

ベストアンサー

SFINAE の基本原則は

テンプレートの展開に失敗したならばその候補は除外される

です。

質問者の例では ft::iterator_traits の展開には成功した上で展開結果がエラーなので、 ft::is_sameft::enable_if に渡る以前にエラーが確定してしまっている状態であると考えられます。


よく見たら違うかも。

依存名は推論できないです。 std::enable_if は返却値の型のところに書くのが基本ですね。

投稿2021/03/03 07:42

編集2021/03/03 09:03
SaitoAtsushi

総合スコア5684

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

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

yoshiki_iwasa

2021/03/09 06:10

ありがとうございます! std::enable_if を書き換えて、いくつかモジュールを追加してうまくいきました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問