Reputation: 113
I want to enable and disable a function declaration in a template class, just based on if the template parameter has one type defined or not for which I use boost/tti/has_type.hpp
. However, I got the complains from compiler, i.e., 'enable_if' cannot be used to disable this declaration.
#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;
}
How could I resolve it? However, if I change it to similar non-member function template, it works.
#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;
}
Upvotes: 0
Views: 232
Reputation: 66200
if I change it to similar non-member function template, it works.
The point is: funtion template.
Your code doesn't works because SFINAE works over templates, with test related to the template parameter. Your contains()
method is a function, inside a template class, but isn't a template function.
To make SFINAE works for contains()
, you have to transform it in a template function.
You have seen that works outside the class, but works also inside the class.
For example, with the following trick (caution: code not tested)
// .......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(); }
Observe that the SFINAE test (has_type_key_type<C>::value
) now involve C
, the function's template parameter, not container
, the template parameter of the class.
If you want avoid that constains()
can be "hijacked" (explicitly setting a type for C
, different from container
, you can add a variadic non-type (and unused) template parameter.
For example
// .......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(); }
Off Topic: you you can use at least C++14, you ca use std::enable_if_t
, so
std::enable_if_t<has_type_key_type<C>::value, int> = 0
instead of
typename std::enable_if<has_type_key_type<C>::value, int>::type = 0
Upvotes: 1