2017-08-08 11 views
5

特定のオブジェクトの範囲コンストラクタを実装したいが、2つの入力イテレータのみを受け入れるように制限したい。typeidを使って入力イテレータしか受け付けないようにコンストラクタを実装する方法は?

私はこのコードをgcc 7.1.0でコンパイルしようとしました。

ファイルtest.cpp

#include <vector> 
#include <type_traits> 
#include <typeinfo> 

template <typename Iterator> 
using traits = typename std::iterator_traits<Iterator>::iterator_category; 

template <typename T> 
class A{ 
    private: 

     std::vector<T> v; 

    public: 

     template <typename InputIterator, 
       typename = std::enable_if_t< 
        typeid(traits<InputIterator>) == 
        typeid(std::input_iterator_tag)> 
       > 
     A(InputIterator first, InputIterator last) : v(first, last) {} 
}; 

int main(){ 
    std::vector<double> v = {1, 2, 3, 4, 5}; 
    A<double> a(v.begin(), v.end()); 
} 

私はg++ test.cpp -o testと、このコンパイルエラーを取得:

test.cpp: In function ‘int main()’: 
    test.cpp:27:34: error: no matching function for call to ‘A<double>::A(std::vector<double>::iterator, std::vector<double>::iterator)’ 
     A<double> a(v.begin(), v.end()); 
            ^
    test.cpp:22:7: note: candidate: template<class InputIterator, class> A<T>::A(InputIterator, InputIterator) 
     A(InputIterator first, InputIterator last) : v(first, last) {} 
     ^
    test.cpp:22:7: note: template argument deduction/substitution failed: 
    test.cpp: In substitution of ‘template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = ((const std::type_info*)(& _ZTISt26random_access_iterator_tag))->std::type_info::operator==(_ZTISt18input_iterator_tag); _Tp = void]’: 
    test.cpp:18:16: required from here 
    test.cpp:19:49: error: call to non-constexpr function ‘bool std::type_info::operator==(const std::type_info&) const’ 
        typeid(traits<InputIterator>) == 
    test.cpp:18:16: note: in template argument for type ‘bool’ 
        typename = std::enable_if_t< 
        ^~~~~~~~ 
    test.cpp:10:7: note: candidate: A<double>::A(const A<double>&) 
    class A{ 
     ^
    test.cpp:10:7: note: candidate expects 1 argument, 2 provided 
    test.cpp:10:7: note: candidate: A<double>::A(A<double>&&) 
    test.cpp:10:7: note: candidate expects 1 argument, 2 provided 

コンストラクタのために、より適しているので、私は、デフォルトのテンプレートパラメータを使用することにしました。オペレータtypeid()を使用するのは、コードを修正するときに読むのが本当に簡単だからですが、どのような方法でも動作させることはできません。

他の解決策は非常に奇妙で、実際にはわかりにくいです(InputIteratorパラメータに* itや++などの特定のメソッドを持たせるなど)。私がこれを行う方法がない場合は、多かれ少なかれ、読みやすいソリューションに感謝します。

答えて

3

関係する式の評価はコンパイル時に行われます。typeidために以下が適用される:

多相型の発現に適用された場合、 型ID発現の評価は、ランタイムオーバーヘッド(仮想テーブル 参照)を含むことができる、そうでなければ型ID式は、コンパイル時に解決されます。

したがって、私はtypeidを静的(コンパイル時)多型に適したオプションとは考えません。次のようにあなたはあなたの問題を解決することができ

一つの方法は、委任costructorとの組み合わせで派遣タグを使用することです:

template <typename T> 
class A{ 
    std::vector<T> v; 

    template <typename InputIterator> 
    A(InputIterator first, InputIterator last, std::input_iterator_tag) : v(first, last) {} 

public: 

    template<typename InputIterator> A(InputIterator first, InputIterator last) 
    : A(first, last, typename std::iterator_traits<InputIterator>::iterator_category()) {} 
}; 

Live Demo

+0

私はこのアイデアを考えたことがありません。理解して実装するのは簡単です。どうもありがとうございました! –

1

オペレータを使用しているのは、コードを作成するときに読みやすいと思っているからですが、どのような方法でも動作させることはできません。

typeidは主に実行で型情報を照会するために使用される機能です。あなたはもっと「読みやすい」と感じるかもしれませんが、それは仕事のための適切なツールではなく、他のすべてのC++開発者を混乱させるでしょう。


他のソリューションは、(例えば*it++itなどの特定のメソッドを持つようにInputIteratorパラメータを強制するように)非常に奇妙に見えると本当にあいまいです

私は強くこれを再考することをアドバイス。あるタイプに対して有効な操作を記述するInputIterator is a concept。コンセプトの背後にある全体の考え方は、操作の有効性をチェックすることです。InputIterator以上はits requirements以上です。

あなたの問題はtrueTもしマッチInputIteratorの要件を返すconstexpr bool is_input_iterator<T>変数/関数を作成して解決するのが正しいと慣用的な方法。 detection idiomを使って簡単に実装することができます。std::enable_if_t<is_input_iterator<T>>よりも読みやすくなりません。ここで

簡略化した例(私はすべての要件をチェックしていないよ):あなたが保証する必要があるSFINAEを行うために

template <typename T> 
using supports_increment = decltype(++std::declval<T>()); 

template <typename T> 
using supports_dereference = decltype(*std::declval<T>()); 

template <typename T> 
constexpr bool is_input_iterator = 
    std::experimental::is_detected_v<supports_increment, T> 
&& std::experimental::is_detected_v<supports_dereference, T>; 

template <typename InputIterator, 
      typename = std::enable_if_t<is_input_iterator<InputIterator>>> 
    A(InputIterator first, InputIterator last) : v(first, last) {} 

live example on wandbox

+0

それは本当にエレガントなソリューションを見て、考えを表現していても入力イテレータの概念は、私はまだ 'decltype'を含むすべてのものと闘う。また、私は**検出イディオムについて聞いたことがありません**、それはまだ標準(私が間違っている場合は私を修正する)のように見える、と私は実際にどのように動作するのか分かりません。 –

+0

'decltype'と検出イディオムがどのように機能するかを説明する無料のオンラインリソースがたくさんあります。ここから始めましょう:https://www.youtube.com/watch?v=o1ekBpEFcPc –

+0

ありがとうございました!私は可能な限りすべての宣言型の世界に浸透しようとします。 –

関連する問題