Reputation: 170469
I have a class template that contains two similar member functions:
template<class T>
class MyTemplate {
// other stuff, then
static T* member( T& ); //line 100
static const T* member( const T& ); //line 101
};
which I instantiate like this:
MyTemplate<int* const>
and Visual C++ 9 complains:
mytemplate.h(101) : error C2535: 'int* MyTemplate<T>::member(T &)' :
member function already defined or declared
with
[
T=int *const
]
mytemplate.h(100) : see declaration of 'MyTemplate::member'
with
[
T=int *const
]
somefile.cpp(line) : see reference to class template instantiation
'MyTemplate<T>' being compiled
with
[
T=int *const
]
I certainly need the two versions of member()
- one for const reference and one for non-const reference. I guess the problem has something with top-level const qualifiers, but can't deduce how to solve it.
How do I resolve this problem so that I still have two versions of member()
and the template compiles?
Upvotes: 1
Views: 239
Reputation: 136208
A simple solution would be to disable the function if T
is const
:
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_const.hpp>
template<class T>
class MyTemplate {
static T* member( T& );
struct Disabled {};
static const T* member(typename boost::mpl::if_<boost::is_const<T>, Disabled, const T&>::type);
};
Upvotes: 1
Reputation: 3432
When T
is int * const
, T
is already const
, so T&
and const T&
are both int * const
.
Or do you mean in this case, you need your class to look like:
class MyTemplate_int_p_const{
static int * member (int *&);
static int * const member (int * const &);
};
You can add this to your main template to achieve this:
template<class T>
class MyTemplate<const T>
{
static T * member(T&);
static const T* member(const T&);
};
As a responds to the OP's comment, if you don't want to use partial specialization, you'll need type_traits. It is supported by C++0x, and for VC++9, you can use boost.
In the following code, the non_const version of member
will take a dummy_type
( a pointer to member function) if T
is already const. So the non_const overload would not exist.
#include <type_traits>
template<class T>
class MyTemplate {
// other stuff, then
//void dummy(void);
typedef void (*dummy_type)(void);
typedef typename std::conditional<std::is_const<T>::value, dummy_type, T>::type T_no_const;
typedef typename std::remove_const<T>::type T_remove_const;
static T_no_const* member( T_no_const& t ) //line 100
{
if (std::is_same<T, T_no_const>::value)
{
return member_portal(t);
}
else
return NULL;
}
static T_no_const* member_portal(dummy_type&){return NULL;};
static T_remove_const* member_portal(T_remove_const&);
static const T* member( const T& ); //line 101
};
int main()
{
MyTemplate<int * const> mt;
MyTemplate<int *> mtt;
return 0;
}
This is the first time that I play with type_traits
. It can pass compilation under g++ 4.5.2 with C++0x enabled. But I've never run it.
Main idea is, when T
is const, the non_const version of member takes a argument of an arbitrary type ( a type that is not likely to be used any where else, and to not likely to be implicitly converted to), thus the non_const version disappears. But in the way, the logic breaks in the implementation of member
( as the argument type is to be used, but is not expected). So the main logic of member
is move another function of member_portal
.
Upvotes: 2
Reputation: 34618
The explanation given by fefe is correct. Foo const&
and Foo const const&
will simply evaluate to the same type, hence your function overloading does not work. In case your template argument is const, I'd suggest specialisation.
Version A:
template<class T>
class MyTemplate {
static T* member( T& );
static const T* member( const T& );
};
template<class T>
class MyTemplate<T const> {
static const T* member( const T& );
};
Version B:
template<class T>
class MyTemplate_mutableImpl {
static T* member( T& );
};
template<class T>
class MyTemplate_constImpl {
static const T* member( const T& );
};
template<class T>
class MyTemplate : public MyTemplate_mutableImpl<T>, public MyTemplate_constImpl<T> {
};
template<class T>
class MyTemplate<T const> : public MyTemplate_constImpl<T const> {
};
Upvotes: 2