Как решить эту проблему с помощью const верхнего уровня? - PullRequest
1 голос
/ 13 декабря 2011

У меня есть шаблон класса, который содержит две похожие функции-члена:

template<class T>
class MyTemplate {
   // other stuff, then
   static T* member( T& ); //line 100
   static const T* member( const T& ); //line 101

};

, который я создаю следующим образом:

MyTemplate<int* const>

и Visual C ++9 жалоб:

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 
]

Мне, безусловно, нужны две версии member() - одна для константной ссылки и одна для неконстантной ссылки.Я полагаю, что проблема связана с квалификаторами const верхнего уровня, но я не могу определить, как ее решить.

Как мне решить эту проблему, чтобы у меня все еще оставалось две версии member(), и шаблон компилируется

Ответы [ 3 ]

2 голосов
/ 13 декабря 2011

Объяснение, данное fefe, является правильным. Foo const& и Foo const const& просто оценят один и тот же тип, поэтому перегрузка вашей функции не работает. В случае, если ваш аргумент шаблона является const, я бы предложил специализацию.

Версия 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& );
};

Версия 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> {
};
2 голосов
/ 13 декабря 2011

Когда T равно int * const, T уже равно const, поэтому T& и const T& равны int * const.

Или вы имеете в виду, что в этом случае ваш класс должен выглядеть так:

class MyTemplate_int_p_const{
     static int * member (int *&);
     static int * const member (int * const &);
};

Вы можете добавить это в свой основной шаблон для достижения этого:

template<class T>
class MyTemplate<const T>
{
    static T * member(T&);
    static const T* member(const T&);
};

В ответ на комментарий ОП, если вы не хотите использовать частичную специализацию, вам понадобятся type_traits. Он поддерживается C ++ 0x, а для VC ++ 9 вы можете использовать boost .

В следующем коде не-const версия member примет dummy_type (указатель на функцию-член), если T уже является const. Таким образом, перегрузка non_const не будет существовать.

#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;
}

Я впервые играю с type_traits. Он может пройти компиляцию под g ++ 4.5.2 с включенным C ++ 0x. Но я никогда не запускал его.

Основная идея заключается в том, что когда T равно const, версия элемента non_const принимает аргумент произвольного типа (тип, который вряд ли будет использоваться где-либо еще, и вряд ли будет неявно преобразован в) таким образом версия non_const исчезает. Но, между прочим, логика ломается при реализации member (так как тип аргумента должен использоваться, но не ожидается). Таким образом, основная логика member заключается в перемещении другой функции member_portal.

0 голосов
/ 13 декабря 2011

Простым решением было бы отключить функцию, если T равно 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);
};
...