![](/img/trans.png)
[英]Initializing boost::shared_ptr<std::vector<T>> with boost::shared_ptr<std::list<T>>
[英]Error converting form boost::shared_ptr<T> to std::shared_ptr<T>
我寫了一個函數模板,通過遵循這個提議將boost::shared_ptr<T>
“轉換”/重新打包到std::shared_ptr<T>
,反之亦然。 它的正常工作,除非我有一個boost::shared_pt<T>
和類型T
是一個抽象類。
到目前為止我想到的是,當boost/shared_ptr.hpp
和boost/shared_array.hpp
一起包含時會出現問題。 如果僅包含boost/shared_ptr.hpp
則當T
的類型是抽象類時,它正在工作。
我正在使用clang 3.3並提升1.55.0。 如果有人可以告訴我為什么它不起作用以及如何讓它工作,那將是很棒的。
謝謝你的幫助
這是一個最小的例子:
//main.cpp
#include <boost/shared_array.hpp> //removing this include and it's working
#include <boost/shared_ptr.hpp>
#include <memory>
template<typename SharedPointer> struct Holder {
SharedPointer p;
Holder(const SharedPointer &p) : p(p) {}
Holder(const Holder &other) : p(other.p) {}
Holder(Holder &&other) : p(std::move(other.p)) {}
void operator () (...) const {}
};
template<class T>
std::shared_ptr<T> to_std_ptr(const boost::shared_ptr<T> &p)
{
typedef Holder<std::shared_ptr<T>> H;
if(H *h = boost::get_deleter<H, T>(p)) // get_deleter seems to cause the problem
{
return h->p;
}
else
{
return std::shared_ptr<T>(p.get(), Holder<boost::shared_ptr<T>>(p));
}
}
這里我用來測試它的代碼:
//main.cpp
template<typename T> class Base
{
public:
T value;
virtual void abstract() = 0;
virtual ~Base() {}
};
template<typename T> class Derived : public Base<T>
{
public:
virtual void abstract() override {}
virtual ~Derived() {}
};
int main(int argc, const char * argv[])
{
boost::shared_ptr<Base<int>> ptr{new Derived<int>()};
// error here
std::shared_ptr<Base<int>> a = to_std_ptr(ptr);
// no error here
std::shared_ptr<Base<int>> b = to_std_ptr(boost::static_pointer_cast<Derived<int>>(ptr));
return 0;
}
這是錯誤消息(縮寫):
boost/smart_ptr/shared_array.hpp:111:102: error: array of abstract class type 'Base<int>'
shared_array( shared_array<Y> const & r, typename boost::detail::sp_enable_if_convertible< Y[], T[] >::type = boost::detail::sp_empty() )
main.cpp:64:40: note: in instantiation of template class 'boost::shared_array<Base<int> >' requested here
if(H *h = boost::get_deleter<H, T>(p))
main.cpp:86:36: note: in instantiation of function template specialization 'to_std_ptr<Base<int> >'requested here
std::shared_ptr<Base<int>> i = to_std_ptr(ptr);
main.cpp:23:18: note: unimplemented pure virtual method 'abstract' in 'Base'
virtual void abstract() = 0;
我從錯誤消息中得到的是編譯器試圖創建一個抽象類數組當然不起作用。 但是為什么他甚至試圖這樣做以及什么boost/sharred_array
與之相關。 他是否可能為boost::get_deleter
選擇了錯誤的重載?
以下是錯誤來源的一個小例子:
struct abstract
{
virtual void foo() = 0;
};
template<class X, class Y>
struct templ {};
template<class T>
struct bar
{
template<class U>
bar(templ<U[], T[]>) {} // (A)
};
int main()
{
bar<abstract> x;
}
在(A)
形成[abstract-type]的類型數組似乎是非法的,因此使用參數abstract
實例化類模板bar
會使程序格式錯誤。
在shared_array
的背景中也發生了同樣的事情。 但為什么shared_array<Base>
實例化?
自由函數boost::get_deleter
被重載, shared_array.hpp
為重載集添加了一個重載(實際上,添加了一個模板):
template< class D, class T > D * get_deleter( shared_array<T> const & p );
在重載解析之前,甚至在找出哪些函數可行之前,需要實例化函數模板。 實例化上面的get_deleter
模板會導致實例化shared_array<Base>
,這會導致程序get_deleter
。
解決的辦法是,不要讓上面的實例化:不提供模板參數T
,也不能推斷出T
的shared_array<T>
從shared_ptr<T>
這兩種類型無關。
更改
if(H *h = boost::get_deleter<H, T>(p))
至
if(H *h = boost::get_deleter<H>(p))
它的工作原理。
解釋為什么讓T
推導起作用:
在編寫函數調用時,可以使用函數模板(查看名稱),必須設置模板參數。 您可以顯式提供它們(在<>
如在get_deleter<H, T>
)。 如果沒有顯式地提供所有這些(如在get_deleter<H>
),則必須從函數調用的參數中推導出其余的。
在顯式設置或推導出所有模板參數后,將替換它們在函數模板中的出現次數。 在此步驟中使用get_deleter<H, Derived>
時出錯:替換的get_deleter
如下所示:
template<> H * get_deleter( shared_array<Derived> const & p );
這里,需要實例化shared_array<Derived>
。 但在此實例化過程中,會出現上述錯誤。 (注意:它不在get_deleter
的直接上下文中,因此SFINAE不適用。)
現在,當您沒有明確提供第二個模板參數時,必須推導出它。 並且這個演繹在功能模板中失敗了
template< class D, class T > D * get_deleter( shared_array<T> const & p );
如果使用shared_ptr<Derived>
類型的參數表達式。 由於演繹失敗,因此不會對函數模板進行實例化,因此不會對shared_array<Derived>
實例化(演繹失敗=無法設置某些模板參數)。
為什么演繹失敗? 編譯器需要從參數表達式中推導出函數參數類型shared_array<T> const&
的模板參數T
,該表達式的類型為shared_ptr<Derived>
。 但是,當函數參數類型可以等於參數表達式類型時,這種推論只能成功(少數例外)。 即,只有存在某種類型X
才能成功,這樣shared_array<X>
與shared_ptr<Derived>
類型相同。 但是沒有: shared_ptr
和shared_array
是不相關的。
因此,不能推導出此get_deleter
重載的模板參數T
; 因此,此函數模板未實例化,並且未實例化shared_array<Derived>
。
扣除失敗是一種特殊的失敗(如SFINAE):它不會導致程序格式錯誤(即它不會導致編譯錯誤)。 相反,演繹沒有成功的函數模板根本不會向重載集添加函數。 如果重載集中還有其他函數,則可以調用其中一個函數。
另一個功能模板
template<class D, class T> D * get_deleter( shared_ptr<T> const & p )
來自boost/smart_ptr/shared_ptr.hpp
運行相同的過程。 但是,此處的推論成功,並且特殊化get_deleter<H, T>
(來自to_std_ptr
的H
和T
)被添加到重載集。 稍后將通過重載決策來選擇它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.