简体   繁体   中英

c++ template specialization for container of reference_wrapper

#include "stdafx.h"

#include <algorithm>

class MyClass {
};

template <typename C, typename V, typename Enable = void>
static bool Contains(const C& container, const V& value) {
    auto iter = std::find(container.begin(), container.end(), value);
    auto result = (iter != container.end());
    return result;
}

template <typename C, typename V,
          typename std::enable_if<std::is_same<std::reference_wrapper<const V>, typename C::value_type>::value, bool>::type>
static bool Contains(const C& container, const V& value) {
    auto iter = std::find_if(container.begin(), container.end(), [&](auto& aValue) {
        return (aValue.get() == value);
    });
    auto result = (iter != container.end());
    return result;
}

int main() {
    const MyClass a;
    auto container = {
        std::reference_wrapper<const MyClass>(a),
    };
    Contains(container, a);
    return 0;
}

Compiler: VC++2015U3

Compile error:

Severity Code Description Project File Line Suppression State Error C2678 binary '==': no operator found which takes a left-hand operand of type 'const std::reference_wrapper' (or there is no acceptable conversion) ConsoleApplication1 c:\\program files (x86)\\microsoft visual studio 14.0\\vc\\include\\xutility 3258

It runs into the first implementation rather than the second one.

Any idea about this?

You need to define operator == to compare class instances:

bool operator ==(MyClass const & left, MyClass const & right) { return false; }

This operator will be invoked by std::find and std::find_if algorithms (rather inside of lambda return (aValue.get() == value); in the second case).

Maybe you need also an operator==() for MyClass but, to solve the specialization problem, I think is better to use an explicit specialization

template <template <typename...> class C, typename V>
static bool Contains (C<std::reference_wrapper<V const>> const & container,
                      V const & value) {
    auto iter = std::find_if(container.begin(), container.end(), [&](auto& aValue) {
        return (aValue.get() == value);
    });
    auto result = (iter != container.end());
    return result;
}

instead of SFINAE.

Because if you also make SFINAE works to enable the reference-wrapper-container version, by example

template <typename C, typename V> 
static std::enable_if_t<std::is_same<std::reference_wrapper<const V>, 
                        typename C::value_type>::value, bool>
   Contains (const C& container, const V& value)

both versions of Contains() function matches the call

 Contains(container, a);

and no one is preferred.

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