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
我想启用和禁用模板中的函数声明 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