c++03:由于enable_if,相互排斥的方法

c++03: Mutually exclusive methods thanks to enable_if

本文关键字:方法 由于 enable if c++03      更新时间:2023-10-16

在一个类中,我有两种不同的方法,它们应该相互排斥,具体取决于调用者模板参数。

class Foo
{
    // For collections
    template<class T>
    typename boost::enable_if<boost::is_same<typename std::vector<typename T::value_type>, T>::value, const T&>::type
    doSomething()
    { }

    // For single types
    template<class T>
    typename boost::enable_if<!boost::is_same<typename std::vector<typename T::value_type>, T>::value, const T&>::type
    doSomething()
    { }
}

这不会编译。

错误:"模板结构提升::enable_if"模板参数列表中参数 1 的类型/值不匹配 错误:需要类型,得到'!提升::is_same::值'

怎么样:

template <typename T> struct is_std_vector : std::false_type {};
template <typename T, typename A>
struct is_std_vector<std::vector<T, A>> : std::true_type {};

然后

class Foo
{
    // For collections
    template<class T>
    typename std::enable_if<is_std_vector<T>::value, const T&>::type
    doSomething();
    // For single types
    template<class T>
    typename std::enable_if<!is_std_vector<T>::value, const T&>::type
    doSomething();
};

与 std 的版本不同,boost::enable_if 接受一个类型(布尔值下的包装器(,所以你应该写类似的东西

class Foo
{
    // For collections
    template<class T>
    typename boost::enable_if<
        typename boost::is_same<typename std::vector<typename T::value_type>, T>,
    const T&>::type doSomething()
    { }

    // For single types
    template<class T>
    typename boost::enable_if_с<
        !boost::is_same<typename std::vector<typename T::value_type>, T>::value,
    const T&>::type doSomething()
    { }
}

请注意,我在boost::is_same之前使用过typename,并且在第一个规范中没有使用::value。相反,我不得不在第二次重载中使用enable_if_с !因为运算符不适用于类型。

一种标签调度呢?

#include <vector>
#include <iostream>
template <typename, typename>
struct isSame
 { typedef int type; };
template <typename T>
struct isSame<T, T>
 { typedef long type; };
struct foo
 {
   template <typename T>
   T const & doSomething (T const & t, int)
    { std::cout << "int version" << std::endl; return t; }
   template <typename T>
   T const & doSomething (T const & t, long)
    { std::cout << "long version" << std::endl; return t; }
   template <typename T>
   T const & doSomething (T const & t)
    { return doSomething(t, typename isSame<
        typename std::vector<typename T::value_type>, T>::type()); }
 };
int main ()
 {
   foo f;
   std::vector<int> v;
   f.doSomething(v);   // print "long version"
 }

如果你想要的是根据是否给你一个向量来重载函数

#include <type_traits>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
class Foo {
public:
    // For collections
    template <class T>
    const vector<T>& do_something(const std::vector<T>& input) {
        cout << __PRETTY_FUNCTION__ << endl;
        return input;
    }

    // For single types
    template <class T>
    const T& do_something(const T& input) {
        cout << __PRETTY_FUNCTION__ << endl;
        return input;
    }
};
int main() {
    auto foo = Foo{};
    auto v = std::vector<int>{};
    auto i = int{};
    foo.do_something(v);
    foo.do_something(i);
}

如果您想更通用并检查任何实例化类型

#include <type_traits>
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
namespace {
    template <typename T, template <typename...> class TT>
    struct IsInstantiationOf
            : public std::integral_constant<bool, false> {};
    template <template <typename...> class TT, typename... Args>
    struct IsInstantiationOf<TT<Args...>, TT>
            : public std::integral_constant<bool, true> {};
} // namespace anonymous
class Foo {
public:
    // For collections
    template <typename VectorType, typename std::enable_if_t<IsInstantiationOf<
            std::decay_t<VectorType>, std::vector>::value>* = nullptr>
    void do_something(VectorType&&) {
        cout << "Vector overload" << endl;
    }
    // For single types
    template <class T, typename std::enable_if_t<!IsInstantiationOf<
            std::decay_t<T>, std::vector>::value>* = nullptr>
    void do_something(T&&) {
        cout << "Non vector overload" << endl;
    }
};
int main() {
    auto foo = Foo{};
    auto v = std::vector<int>{};
    auto i = int{};
    foo.do_something(v);
    foo.do_something(i);
}

另请注意,出于以下原因,您应该尽可能避免在函数签名中放入std::enable_if https://stackoverflow.com/a/14623831/5501675