It appears that you want to make the set method available only if the argument is T or int. However, if you just specialize C for int, all the implicit conversions still happen, just as if you didn't attempt to treat int type in a special way at all.
If you really want to disable implicit conversions, one way is with boost::enable_if
- make the method only available, if the criteria are satisfied.
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
template<typename T>
struct C
{
T member;
template <class U>
typename boost::enable_if_c<
boost::is_same<T, U>::value || boost::is_same<U, int>::value
>::type
set(const U& x) { member = x; }
};
int main()
{
C<int> i;
i.set(3.14); //error
i.set(10); //OK
i.set('a'); //error
C<double> d;
d.set(3.14); //OK
d.set(3.14f); //error
d.set(10); //OK
d.set('a'); //error
}
To achieve the same result without boost::enable_if
(or implementing it yourself), you might also need to make all unwanted versions of set private (C++0x also allows to delete these overloads).
template<typename T>
struct C
{
T member;
void set(const T& x) { member = x; }
void set(int x) { member = x; }
private:
template <class U>
void set(const U&);
};
template <>
struct C<int>
{
int member;
void set(int x) { member = x; }
private:
template <class U>
void set(const U&);
};
int main()
{
C<int> i;
i.set(3.14); //error
i.set(10); //OK
i.set('a'); //error
C<double> d;
d.set(3.14); //OK
d.set(3.14f); //error
d.set(10); //OK
d.set('a'); //error
}
However, making this exception for int seems rather arbitrary to me. Conversions from int might not be particularly safe, either, e.g int->float
might lose precision for large values, int->short
/ int->char
/ int->unsigned
might overflow.