2016-10-20 5 views
1

イテレータの型やその他の型に異なる値を出力する関数を記述したいと思います。いくつかの研究を行った後、ここに私が思い付いたものです:C++のさまざまな関数に異なる型をディスパッチするためのコードを簡略化

#include <iostream> 
#include <iterator> 
#include <experimental/type_traits> 

namespace details 
{ 
    template <class T, class = void> 
    struct is_iterator : std::false_type 
    { 
    }; 

    template <class T> 
    struct is_iterator<T, std::experimental::void_t<typename std::iterator_traits<T>::value_type>> : std::true_type 
    { 
    }; 

    template <class T> 
    constexpr auto is_iterator_v = is_iterator<T>::value; 
} 

template <class T> 
std::enable_if_t<!details::is_iterator_v<T>> print(const T &value) 
{ 
    std::cout << value; 
} 

template <class T> 
std::enable_if_t<details::is_iterator_v<T>> print(const T &value) 
{ 
    std::cout << "(IteratorTo "; 
    print(*value); 
    std::cout << ')'; 
} 

しかし、私は私のコードは少し長すぎると、少し複雑だと思います。私のコードを短くしてきれいにすることは可能ですか?

答えて

3

SFINAEはここにあなたの友達です。また

template <class T> 
constexpr std::true_type is_iterator(typename std::iterator_traits<T>::value_type*, int) 
{ 
    return {}; 
} 

template <class T> 
constexpr std::false_type is_iterator(void*, long) 
{ 
    return {}; 
} 

template <class T> 
constexpr auto is_iterator_v = is_iterator<T>(nullptr, 0); 

、あなたは以上の読み見つけられない場合があり、タグ・ディスパッチを使用してprintの代替実装、:

template <class T> 
void print(const T &); 

namespace details 
{ 
    template <class T> 
    void print(const T &value, std::false_type) 
    { 
     std::cout << value; 
    } 

    template <class T> 
    void print(const T &value, std::true_type) 
    { 
     std::cout << "(IteratorTo "; 
     print(*value); 
     std::cout << ')'; 
    } 
} 

template <class T> 
void print(const T &value) 
{ 
    details::print(value, details::is_iterator_v<T>); 
} 
+0

'void_t'を削除するとコードが壊れているようです。 – aschepler

+0

http://coliru.stacked-crooked.com/a/20ee221e917fa468 – aschepler

+0

@aschepler:すべての公平なポイント!私の恥知らずの怠け者。 > _> – ildjarn

0

あなたの解決策はシンプルで、短く、きれいです。

質問にはC++ 14というタグが付けられていますが、std::experimental::void_tというコードを使用することをお勧めします。

しかし(私が間違っていない場合)、void_tを使わずに同じ結果を得ることができました。これは、古いdecl3のカンマを使っています。

次のようにして、((感謝)Ildjarnによって指さ問題修正しようとしている修正!)あなたのstd::true_typeバージョンを書き込むことができます。

template <typename T> 
struct is_iterator<T, 
    decltype(std::declval<typename std::iterator_traits<T>::value_type>(), 
     void())> : std::true_type 
{ }; 

このソリューションは、あまりにもC++ 11で動作するはずですが。

+0

これはその 'VALUE_TYPEが必要です'はデフォルトで構成可能です。かなり強い要件! – ildjarn

+0

@ildjarn - D'oh!あなたが正しい。あまりにも強い要件。もし私が間違っているなら私を訂正してください: 'std :: declval'はこの問題を解決するはずですね。 (私の変更された答えを見てください) – max66

+0

確かに! _ _ – ildjarn

関連する問題