简体   繁体   中英

Assignable reference to both lvalues and rvalues

Suppose I have a function unique_count that can count the number of unique elements in any unsorted range:

template<typename InputIt>
std::size_t unique_count(InputIt first, InputIt last)
{
    using T = typename std::iterator_traits<InputIt>::value_type;

    std::vector</* ??? */> v(first, last);
    std::sort(v.begin(), v.end());
    return std::distance(v.begin(),
                         std::unique(v.begin(), v.end()));
}

I create a new vector because I don't want to modify the original container, but I also don't want to do unnecessary copying. The easiest solution is to make a vector of pointers, but a problem is *first may return either a const T& (eg, from a vector ), or a T (eg, from a stream).

The /* ??? */ /* ??? */ part should therefore be conceptually equivalent to const T& . We can't really do this, since vector s can't hold references, which are unassignable. We can't use reference_wrapper<const T> either, because it's not constructible from temporaries.

What alternatives do I have?

You want /* ??? */ /* ??? */ to be a type that may or may not own a T object, depending on whether it was constructed with a temporary T or a const T& . For obvious reasons, such types should generally be avoided.

One alternative is to use tag dispatch or SFINAE to select one of two possible implementations, depending on whether *first returns a reference or non-reference type.

Another alternative is to narrow your algorithm a bit so that it only accepts forward iterators. Here you are guaranteed to be able to simply store iterators themselves and use them to compare the elements pointed to:

template <typename ForwardIt>
std::size_t unique_count(ForwardIt first, ForwardIt last) {
    std::vector<ForwardIt> v;
    for (auto i = first; i != last; ++i) {
        v.push_back(i);
    }
    const auto pred = [](ForwardIt a, ForwardIt b) { return *a < *b; };
    std::sort(v.begin(), v.end(), pred);
    return std::distance(v.begin(), std::unique(v.begin(), v.end(), pred));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM