SFINAE:'enable_if' 不能用于禁用此声明

SFINAE: 'enable_if' cannot be used to disable this declaration

我想启用和禁用模板中的函数声明 class,仅基于模板参数是否定义了我使用的一种类型 boost/tti/has_type.hpp。但是,我收到编译器的投诉,即 'enable_if' 不能用于禁用此声明。

#include <boost/tti/has_type.hpp>
#include <iostream>
#include <vector>
#include <set>
using namespace std;

BOOST_TTI_HAS_TYPE(key_type)

template <typename container>
class adapter : public container
{
public:
    using container::container;
public:
    template <typename type = typename enable_if<!has_type_key_type<container>::value,typename container::value_type>::type>
    bool contains(typename container::value_type const & v) { return find(begin(*this),end(*this),v) != end(*this); }

    template <typename type = typename enable_if<has_type_key_type<container>::value,typename container::value_type>::type>
    bool contains(typename container::key_type const & k) { return this->find(k) != this->end(); }
};

int main()
{
    cout << has_type_key_type<adapter<vector<int>>>::value << endl;
    cout << has_type_key_type<adapter<set<int>>>::value << endl;
}

我该如何解决?但是,如果我把它改成类似的非成员函数模板,它就可以了。

#include <boost/tti/has_type.hpp>
#include <iostream>
#include <vector>
#include <set>
using namespace std;

BOOST_TTI_HAS_TYPE(key_type)

template <typename container, typename enable_if<!has_type_key_type<container>::value,int>::type = 0>
bool contains(container const & c, typename container::value_type const & v) { return find(begin(c),end(c),v) != end(c); }

template <typename container, typename enable_if<has_type_key_type<container>::value,int>::type = 0>
bool contains(container const & c, typename container::key_type const & k) { return c.find(k) != c.end(); }

template <typename container>
class adapter : public container
{
public:
    using container::container;
public:
    // ...
};

int main()
{
    vector<double> v{3.14};
    set<double> s{2.71};
    cout << contains(v,3.14) << endl;
    cout << contains(s,2.71) << endl;
}

if I change it to similar non-member function template, it works.

重点是:函数模板.

您的代码不起作用,因为 SFINAE 在模板上运行,测试与模板参数相关。您的 contains() 方法是一个函数,位于模板 class 内,但不是 模板 函数。

要使 SFINAE 为 contains() 工作,您必须在 模板 函数中对其进行转换。

您已经看到它在 class 外有效,但在 class 内也有效。

例如,使用以下技巧(注意:代码未测试)

// .......VVVVVVVVVVVVVVVVVVVVVV
template <typename C = container, // ................V
          typename std::enable_if<!has_type_key_type<C>::value, int>::type = 0>
bool contains (typename container::value_type const & v)
 { return find(begin(*this),end(*this),v) != end(*this); }

// .......VVVVVVVVVVVVVVVVVVVVVV
template <typename C = container, // ...............V
          typename std::enable_if<has_type_key_type<C>::value, int>::type = 0>
bool contains (typename container::key_type const & k)
 { return this->find(k) != this->end(); }

观察 SFINAE 测试 (has_type_key_type<C>::value) 现在涉及函数的模板参数 C,而不是 class 的模板参数 container

如果你想避免 constains() 可以被“劫持”(明确设置 C 的类型,不同于 container,你可以添加可变参数 non-type (和未使用的)模板参数。

例如

// .......VVVVVV
template <int..., typename C = container,
          typename std::enable_if<!has_type_key_type<C>::value, int>::type = 0>
bool contains (typename container::value_type const & v)
 { return find(begin(*this),end(*this),v) != end(*this); }

// .......VVVVVV
template <int..., typename C = container,
          typename std::enable_if<has_type_key_type<C>::value, int>::type = 0>
bool contains (typename container::key_type const & k)
 { return this->find(k) != this->end(); }

题外话:你至少可以使用C++14,你不能使用std::enable_if_t,所以

std::enable_if_t<has_type_key_type<C>::value, int> = 0

而不是

typename std::enable_if<has_type_key_type<C>::value, int>::type = 0