2013-06-03 2 views
12

Я пытаюсь использовать вывод аргумента шаблона с наследованием и std::shared_ptr. Как вы можете видеть в приведенном ниже примере кода, я передаю shared_ptr<Derived> в шаблонную функцию, отличную от члена, которая должна делать вывод аргумента шаблона. Если я вручную назову тип, все будет работать, и если я позволю ему сделать вывод аргумента шаблона, это не так. Было бы кажется, как если бы компилятор не смог определить тип, однако сообщение об ошибке показывает, что это произошло. Я не уверен, что здесь происходит, и я был бы признателен за любой вклад. (Visual Studio 2010)Проблема с вычитанием аргумента std :: shared_ptr, наследования и шаблона

#include <memory> 

template <typename T> 
class Base {}; 

class Derived : public Base<int> {}; 

template <typename T> 
void func(std::shared_ptr<Base<T> > ptr) {}; 

int main(int argc, char* argv[]) 
{ 
    std::shared_ptr<Base<int>> myfoo(std::shared_ptr<Derived>(new Derived)); // Compiles 
    func(myfoo); // Compiles 
    func<int>(std::shared_ptr<Derived>(new Derived)); // Compiles 
    func(std::shared_ptr<Derived>(new Derived)); // Doesn't compile. The error message suggests it did deduce the template argument. 

    return 0; 
} 

Сообщение об ошибке:

5> error C2664: 'func' : cannot convert parameter 1 from 'std::tr1::shared_ptr<_Ty>' to 'std::tr1::shared_ptr<_Ty>' 
5>   with 
5>   [ 
5>    _Ty=Derived 
5>   ] 
5>   and 
5>   [ 
5>    _Ty=Base<int> 
5>   ] 
5>   Binding to reference 
5>   followed by 
5>   Call to constructor 'std::tr1::shared_ptr<_Ty>::shared_ptr<Derived>(std::tr1::shared_ptr<Derived> &&,void **)' 
5>   with 
5>   [ 
5>    _Ty=Base<int> 
5>   ] 
5>   c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\memory(1532) : see declaration of 'std::tr1::shared_ptr<_Ty>::shared_ptr' 
5>   with 
5>   [ 
5>    _Ty=Base<int> 
5>   ] 
5> 
+2

Вот что GCC 4.7.3 должен сказать об этом, FYI: 't.cpp: 9: 6: Примечание: аргумент шаблона вычет/замена не удалась: t.cpp: 16: 47: Примечание: несоответствующие типы ' Base 'и' Derived ' t.cpp: 16: 47: note:' std :: shared_ptr 'не является производным от' std :: shared_ptr > '' –

ответ

10

Хотя компилятор может выполнить полученные на базу преобразования при выполнении типа дедукции, std::shared_ptr<Derived> делает не сами выводят из std::shared_ptr<Base<int>>.

Существует определенное пользователем преобразование между двумя, которое позволяет shared_ptr вести себя как обычные указатели относительно полиморфизма, но компилятор не будет принимать во внимание определяемые пользователем преобразования при выполнении вывода типа.

Без учета определенного пользователя conversiosn, компилятор не может вывести T что бы сделать shared_ptr<Base<T>> либо идентичны shared_ptr<Derived> или базовый класс shared_ptr<Derived> (опять же, shared_ptr<Base<int>> является не базового класс shared_ptr<Derived>).

Следовательно, вычет типа невозможен.

Чтобы обойти эту проблему, вы можете позволить параметр вашей функции быть простой shared_ptr<T>и добавить SFINAE-ограничение, которое будет убедиться, что ваша перегрузка определена только тогда, когда тип аргумента является производным от (или есть) экземпляр шаблона Base класса:

#include <type_traits> 

namespace detail 
{ 
    template<typename T> 
    void deducer(Base<T>); 

    bool deducer(...); 
} 

template <typename T, typename std::enable_if< 
    std::is_same< 
     decltype(detail::deducer(std::declval<T>())), 
     void 
     >::value>::type* = nullptr> 
void func(std::shared_ptr<T> ptr) 
{ 
    // ... 
} 

Вот live example.

+0

К сожалению,' decltype' и др. недоступны в MSVC10. Почему вы не используете 'is_base_of'? – dyp

+1

@DyP: 'decltype' и др. * * доступны в MSVC10 –

+0

@ DyP: Да, кажется, что доступно только 'decltype', а не« al .: »: D Ну, в этом случае мне нужно немного изменить ситуацию, вы правы –

0

Это работает, если вы пишете это так:

template <typename T> 
void func(std::shared_ptr<T> ptr) {}; 

Если вы действительно хотите, чтобы явно блокировать функцию от вызова с чем-то не производным от базы, вы могли бы использовать type_traits/enable_if/др.

Смежные вопросы