1

给定一个范围(可能是一个带有开始/结束迭代器成员的容器),是否有一种可靠的方法来确定其元素的类型?

以下几乎一直有效,但在普通数组上失败。

我已经看到使用该类型的建议,Container::value_type但当然不是为内置数组定义的。

begin(int [3])不知何故,使用 GCC 4.8.1 编译时找不到以下代码。它确实适用于 Microsoft Visual Studio 2012。

#include <iostream>
#include <vector>

// Identify the type of element in given range type.
template<typename Range> struct range_elem {
    typedef typename std::decay<decltype(*std::begin(std::declval<Range>()))>::type type;
};

// Count the number of elements in range matching value.
template<typename Range>
int count(const Range& range, typename range_elem<Range>::type value) {
    int n = 0;
    for (const auto& e : range) { if (e==value) n++; }
    return n;
}

struct S { };
int count(S&, int) { return 10; }  // further test robustness to overload

int main() {
    // This compiles OK.
    std::vector<int> vec; vec.push_back(1); vec.push_back(2); vec.push_back(3);
    std::cerr << count(vec, 2) << "\n";
    //
    int ar[3] = {1,2,3};
    // This compiles OK.
    {
        int n = 0;
        for (const auto& e : ar) { if (e==2) n++; }
        std::cerr << n << "\n";
    }
    // This fails to compile on gcc 4.8.1;
    //  error: no matching function for call to 'begin(int [3])'
    std::cerr << count(ar, 2) << "\n";
    //
    // Somehow realize SFINAE when overloading with a different type that does not support begin/end?
    S s; std::cerr << count(s,2) << "\n";
    return 0;
}
4

1 回答 1

1

首先,请注意这std::begin(ar)是有效的。事实上typename std::decay<decltype(*std::begin(ar))>::type也是有效的。所以问题一定出在其他地方。

当您查看如何std::begin实现时会变得很清楚,例如:

template <typename T, std::size_t N>
T * begin(T (& arr)[N])
{
    return arr;
}

所以它适用于T(&)[N]但不适用于T[N],不幸的是,这decltype(ar)是推断出来的。

如果您将代码更改为:

template<typename Range> struct range_elem {
    typedef typename std::decay<
        decltype(*std::begin(std::declval<Range &>()))
    >::type type;
};

见这里:http: //ideone.com/RoNFZz


在您更新的问题中,您要求使用 SFINAE 来检测您的类型是否与std::begin. 您可以轻松地为此编写一个特征:

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

    template <typename U>
    static yes deduce(decltype(std::begin(std::declval<U const &>())) *);
    template <typename> static no deduce(...);

    static bool constexpr value = sizeof(deduce<T>(0)) == sizeof(yes);
};

或此处的完整代码:http: //ideone.com/W9GLSt

于 2013-09-18T21:33:06.353 回答