3

以下のようにis_iterableテンプレートを作成しました。これは、無料の関数begin / endが(ADLのコンテキストで)使用可能であることを確認し、適切なイテレーターオブジェクトを返します。(これは、ranged-forループ内の反復可能なオブジェクトの要件です)

#include <utility>
#include <iterator>
#include <type_traits>
#include <vector>

template <typename T>
typename std::add_rvalue_reference<T>::type declval(); // vs2010 does not support std::declval - workaround

template <bool b>
struct error_if_false;

template <>
struct error_if_false<true>
{
};

template<typename U>
struct is_input_iterator
{
    enum {
        value = std::is_base_of<
            std::input_iterator_tag,
            typename std::iterator_traits<U>::iterator_category
        >::value
    };
};

template<typename T>
struct is_iterable
{
    typedef char yes;
    typedef char (&no)[2];

    template<typename U>
    static auto check(U*) -> decltype(
        error_if_false<
            is_input_iterator<decltype(begin(declval<U>()))>::value
        >(),
        error_if_false<
            is_input_iterator<decltype(end(declval<U>()))>::value
        >(),
        error_if_false<
            std::is_same<
                decltype(begin(declval<U>())),
                decltype(end(declval<U>()))
            >::value
        >(),
        yes()
    );

    template<typename>
    static no check(...);

public:
    static const bool value = (sizeof(check<typename std::decay<T>::type>(nullptr)) == sizeof(yes));
};

#include <cstdio>
void write(int a)
{
    printf("%d\n", a);
}

template<typename T>
typename std::enable_if<is_iterable<T>::value>::type write(const T& a)
{
    for (auto i = begin(a), e = end(a); i != e; ++i) {
        write(*i);
    }
}

int main()
{
    write(10);

    std::vector<int> a;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    a.push_back(4);

    write(a);
}

上記のコードは、vs2010で意図したとおりに機能しますが、gccでは機能しません。また、以下のように「begin」というランダムなフリー関数を入れると、vs2010でも壊れてしまいます。

int begin(int)
{
}

コードを機能させるにはどうすればよいですか?また、「is_iterable」コンセプトチェッカーを改善する提案をいただければ幸いです。

追加:「書き込み」機能は単なる概念のデモンストレーションの例です。貴重な時間を費やさないでください。(私はそれが最良のコードではないことを知っています:()注意が必要な部分はADLの振る舞いと「is_iterable」テンプレートです:)

4

2 に答える 2

0

/に追加std::すると 、コードは gcc-4.6 でコンパイルおよび実行されます。beginend

error_if_false改善の提案: of に置き換えますenable_if

于 2012-08-10T05:34:50.770 に答える
-1

write(a);Jerryが言ったように、演算子を介して定義する必要があります。コードがきれいになるように、もっと簡潔にするかもしれません。

于 2012-07-08T15:16:38.157 に答える