【问题标题】:SFINAE: 'enable_if' cannot be used to disable this declarationSFINAE:“enable_if”不能用于禁用此声明
【发布时间】:2021-02-18 04:38:57
【问题描述】:

我想启用和禁用模板类中的函数声明,这取决于模板参数是否定义了我使用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;
}

【问题讨论】:

    标签: c++ c++11 templates sfinae typetraits


    【解决方案1】:

    如果我将其更改为类似的非成员函数模板,它可以工作。

    重点是:函数模板

    您的代码不起作用,因为 SFINAE 在模板上工作,测试与模板参数相关。您的 contains() 方法是模板类中的一个函数,但不是 template 函数。

    要使 SFINAE 为 contains() 工作,您必须将其转换为 模板 函数。

    你已经看到了,它在课堂外有效,但在课堂内也有效。

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

    // .......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&lt;C&gt;::value) 现在涉及函数的模板参数 C,而不是类的模板参数 container

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

    例如

    // .......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
    

    【讨论】:

    • 非常感谢 max66,我非常喜欢你的回答。我还是有点疑惑为什么编译器不支持成员函数,也许编译器可以支持,我们所做的似乎让编译器高兴,而我想要的就这么清楚:)
    • 我的意思是模板类的成员函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多