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

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

詳細はこちら
C++

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

Q&A

解決済

1回答

4477閲覧

テンプレート関数のエラー `candidate template ignored: couldn't infer template argument` が解決できない(T^T)

yoshiki_iwasa

総合スコア23

C++

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

0グッド

0クリップ

投稿2021/01/15 03:57

candidate template ignored: couldn't infer template argument の理由がわかりません(TT)

#質問概要

現在、自作でstd::vector を作っているのですが、SFINAE を使ってコンパイルするコンストラクタを分けようとしてるのですが、上記のエラーが出てしまい、ます。
その理由がわかりません....
以前、関連する質問をしたのでそのリンクを載せておきます。

#質問詳細

以下のコードでコンパイルエラーがおきます(自作オブジェクトはft名前空間に作っています)

※ 訳あって、enable_if も自作しています
※ さらに訳あってC++98 の機能しか使ってはいけないので、型判別にはstd::numeric_limits<>::is_integer しか使ってないです

C++

1 2int main() 3{ 4 int k = 4; 5 int array[] = {1,2,3,4,5,6,7,8}; 6 ft::vector<int> a(10, 100); 7 ft::vector<int> b(array, array + 8); <- ここでエラーが出ます 8} 9 10

エラー文

Shell

1main.cpp:22:18: error: no matching constructor for initialization of 'ft::vector<int>' 2 ft::vector<int> b(array, array + 8); 3 ^ ~~~~~~~~~~~~~~~~ 4./vector.hpp:35:12: note: candidate constructor not viable: no known conversion from 'int [8]' to 5 'typename ft::enable_if<std::numeric_limits<size_type>::is_integer, size_type>::type' 6 (aka 'unsigned long') for 1st argument 7 explicit vector( 8 ^ 9./vector.hpp:40:3: note: candidate template ignored: couldn't infer template argument <- 自分としては、このコンストラクタ(下に記載)が起動してほしいけど、してくれない。推論できないとか言われちゃう 10 'InputIterator' 11 vector( 12 ^ 13./vector.hpp:34:12: note: candidate constructor not viable: allows at most single argument 14 'alloc', but 2 arguments were provided 15 explicit vector(const allocator_type& alloc = allocator_type()); 16 ^ 17./vector.hpp:44:3: note: candidate constructor not viable: requires single argument 'x', but 2 18 arguments were provided 19 vector (const vector& x); 20 ^ 211 error generated. 22

自作vector の定義と実装は以下です(コンストラクタの部分のみ)

#####定義

C++

1 2 3 template <class T> 4 class vector 5 { 6 public: 7 /* 8 member values 9 */ 10 typedef T value_type; 11 typedef allocator<T> Allocator; 12 typedef Allocator allocator_type; 13 typedef typename allocator_type::reference reference; 14 typedef typename allocator_type::const_reference const_reference; 15 typedef typename allocator_type::pointer pointer; 16 typedef typename allocator_type::const_pointer const_pointer; 17 typedef typename allocator_type::difference_type difference_type; 18 typedef typename allocator_type::size_type size_type; 19 typedef pointer iterator; 20 typedef const_pointer const_iterator; 21 typedef std::reverse_iterator<iterator> reverse_iterator; 22 typedef std::reverse_iterator<const_iterator> const_reverse_iterator; 23 /* 24 Constructors 25 */ 26 // default 27 explicit vector(const allocator_type& alloc = allocator_type()); 28     29 //fill constructor 30 explicit vector( 31 typename ft::enable_if<std::numeric_limits<size_type>::is_integer ,size_type>::type n, const value_type& val = value_type(), \ 32 const allocator_type& alloc = allocator_type()); 33 34 //range constructor 35 template <class InputIterator> 36 vector( 37 typename ft::enable_if<!std::numeric_limits<InputIterator>::is_integer ,InputIterator>::type first,\ 38 typename ft::enable_if<!std::numeric_limits<InputIterator>::is_integer ,InputIterator>::type last, \ 39 const allocator_type& alloc = allocator_type()); 40//COpy constructor 41 vector (const vector& x); 42

#####実装

// fill constructor template<class T> vector<T>::vector( typename ft::enable_if<std::numeric_limits<size_type>::is_integer ,size_type>::type n,\ const value_type& val, const allocator_type& alloc) { this->_pointer = alloc.allocate(n); this->_size = n; this->_capacity = n; for(size_type i = 0; i < this->_size; i++) { this->_pointer[i] = val; } } // range constructor template<class T> template<class InputIterator> vector<T>::vector( typename ft::enable_if<!std::numeric_limits<InputIterator>::is_integer ,InputIterator>::type first, \ typename ft::enable_if<!std::numeric_limits<InputIterator>::is_integer ,InputIterator>::type last ,\ const allocator_type& alloc) { this->_size = last - first; this->_capacity = last - first; this->_pointer = alloc.allocate(this->_capacity); for(size_type i = 0; i < this->_size; i++) { this->_pointer[i] = *first; first++; } }

問題が出ているのは、fill constructor と range constructor の判別のタイミングです

#####自作の enable_if は以下です

namespace ft { template <bool B, typename T> class enable_if { public: typedef T type; }; template <typename T> class enable_if<false, T> {}; } なぜ、テンプレート引数が推論できないとか言われちゃうんでしょうか... どうか皆さんの知恵を貸してください!!!!!

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

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

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

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

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

guest

回答1

0

ベストアンサー

std::numeric_limits<int[]> が存在しないから、 両方のvectorコンストラクタがエラーになりマッチしないのではないでしょうか。

追記: ↑そんなことはないようです。std::numeric_limits<> はどんな型にも動きます。
原因は、firstlastの両方をenable_if<>::typeにしてしまうと、InputIteratorに何の型を当てはめるか決められなくなるためで、どちらかのenable_if<>をやめればよいです。

ターゲット環境にstd::iterator_traits<>があればそれで判定するのはいかがでしょうか。std::iterator_traits<>がある場合、range constructor のパラメータは

c++

1// イテレータをデリファレンスした型がvectorのvalue_typeと等しいならOK。 2// std::is_same<> はC++11からなので、ft:is_same<> を実装する 3typename ft::enable_if< 4 ft::is_same<std::iterator_traits<InputIterator>::value_type, 5 value_type>::value, 6 InputIterator>::type first,

です。fill constructor に enable_if<> は必要ありません。

投稿2021/01/15 04:55

編集2021/01/15 06:45
int32_t

総合スコア21679

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

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

yoshiki_iwasa

2021/01/15 05:24

回答ありがとうございます!! 今、is_same を作って実験してみます ところで、 >`std::numeric_limits<char[]>` が存在しないから、 両方のvectorコンストラクタがエラーになりマッチしないのではないでしょうか。 について、`std::numeric_limits<char[]>` が存在しないとはどういう意味でしょうか..? std::numeric_limits はテンプレートオブジェクトなので、入ってきたあらゆる型に対して動くものだと思っていました。 なので、今回もstd::numeric_limits<int[]>::is_integer は false を返してくれるかな〜と期待してました
int32_t

2021/01/15 05:40

> std::numeric_limits はテンプレートオブジェクトなので、入ってきたあらゆる型に対して動く そういえばそうですね。どんな型でも動くように定義されているようです。 元のエラーの原因はぱっと見でわかりませんが、fill constructor を消してコンパイルしたら range constructor にマッチしない理由がエラーメッセージに出るかもしれません。
yoshiki_iwasa

2021/01/15 05:49

@SaitoAtushi さん なるほど、 > "Specializations shall be provided for each arithmetic type, both floating point and integer, including bool. The member is_specialized shall be true for all such specializations of numeric_limits." てことは、std::numeric_limits は 浮動小数型が整数型じゃないことや、整数型が整数型であることは判断できるけど、他の算術に関係のない型がきた時は所望の挙動をしないという理解であってますか?
yoshiki_iwasa

2021/01/15 06:03

@int32_t さん is_same を実装して、提案していただいた方法でやってみているのですが、未だにエラーが取れません(T T) やり方が間違ってるんでしょうか 見にくいかもですが,,, ft::is_same template <typename T, typename U> struct is_same { static const bool value = false; }; template <typename T> struct is_same <T, T> { static const bool value = true; }; range constructor vector( typename ft::enable_if<ft::is_same<typename std::iterator_traits<InputIterator>::value_type, value_type>::value, InputIterator>::type first, \ typename ft::enable_if<ft::is_same<typename std::iterator_traits<InputIterator>::value_type, value_type>::value, InputIterator>::type last, \ const allocator_type& alloc = allocator_type());
yoshiki_iwasa

2021/01/15 06:11 編集

あ! こうするとうまく行きました!! range constructor vector( typename ft::enable_if<ft::is_same<typename std::iterator_traits<InputIterator>::value_type, value_type>::value, InputIterator>::type first, \ InputIterator last, \ const allocator_type& alloc = allocator_type()); first と last 両方に enable_if をかけた時はテンプレート引数の推測に失敗していたのに、片方だとうまくいったのはどうしてなのでしょう....???????? (????)
int32_t

2021/01/15 06:32 編集

あーなるほど、両方ともenable_ifにしてしまうと、コンパイラがInputIteratorにどの型を代入すればよいのかわからなくなるのでしょうね。
SaitoAtsushi

2021/01/15 06:37

依存名を推論対象にすることは出来ないです。
yoshiki_iwasa

2021/01/15 07:19

えーと、この場合、両方 enable_if だと、ft::enable_if<>::type が両方定義されなくなる可能性がありますよね その場合、コンパイルエラーが起きる理由は結局何なのでしょう? また、片一方だけだと上手くいくのもなぜかまだあまりわかっていません... どういう判断をコンパイラがしてるんでしょう??
int32_t

2021/01/15 07:39 編集

「vector(array, array+8)」というコードに対して「template <InputIterator> vector(InputIterator first, InputIterator last)」というテンプレートを適用すると、コンパイラは「InputIterator は array の型だ」と決められます。 「template <InputIterator> vector(enable_if<...InputIterator...>::type first, enable_if<...InputIterator...>::type last)」というテンプレートだと、InputIteratorが決まらないと first/last の型がわからないので、array の型が InputIterator かどうかは、コンパイラにはわからないのです。 片方だけでも enable_if をやめれば、引数の型からInputIteratorを決められます。
SaitoAtsushi

2021/01/15 07:45

補足すると、このとき type という型は InputIterator に依存していて、そういうのは推論できるようになってないという話です。
yoshiki_iwasa

2021/01/15 07:56

理解を確認させてください! vector(array, array+8) というコードに対して、first も last も型を InputIterator に依存させている時   template<InputIterator> の InputIterator が何なのかvector()の引数から決まらない すると、enable_if の部分も実行できない そうなると結局InputIteratorが決まらないのでtemplate<InputIterator> で宣言された コンストラクタは適用できない。 結果的に、呼び出すべきコンストラクタが見つからずエラー ってことであってますか?? 依存名は推論対象にならないって部分の理解が甘い気がしますが、どうでしょうか
int32_t

2021/01/15 08:15

その理解でよいと思います。
yoshiki_iwasa

2021/01/15 12:12

ありがとうございます! 昨日からずっと質問に対応してくださってありがとうございました!! 問題が解決しましたし、なにより理解が深まりました! 本件Closeでお願いします!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問