2016-03-16 115 views
3

我試圖製作一些可以讀取或寫入不同類型的文件流。除了具體方法的閱讀部分之外,一切都有效。該方法在調用時返回std::unique_ptr<T>,並且是另一種返回T的方法的「包裝器」。出於某種原因,編譯器不使用此方法,而是嘗試使用另一種方法(返回T)編譯它。因爲這個編譯失敗。我已經嘗試過在互聯網上搜索,但我找不到任何準確的答案。你能幫我解決這個問題嗎?具有相同名稱但返回類型不同的C++模板函數

兩種方法我已經定義:

template <typename T> 
T read() 
{ 
    T obj; 
    obj.readFromFile<T>(); 
    return std::move(obj); 
} 

template < 
    typename T, 
    template<typename> class D, 
    template<typename, typename> class Container 
> 
typename std::enable_if_t< 
    std::is_same<Container<T, D<T>>, std::unique_ptr<T, D<T>>>::value, 
    Container<T, D<T>> 
> 
read() 
{ 
    return std::move(std::make_unique<T, D<T>>(readFromFile<T>())); 
} 

後一種方法是,我試圖調用一個。

當我寫的東西是這樣的:

std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>()

編譯器試圖與第一種方法(template <typename T> T read() {...})和編譯失敗編譯它。如果我首先製作了unique_ptr object,並且將它複製到*unique_ptr<A> object,但是這對我來說並不合適,因爲我在這兩個函數上使用了一些宏,並且我無法在調用宏之前使對象A自己成爲unique_ptr<A> object。僅供參考,我正在使用Visual Studio 2015.

有什麼方法可以使這項工作沒有任何重大修改?我還發現一個建議,基本上說你必須給一個函數添加一個指針參數,然後用static_cast<Obj>(nullptr)作爲參數來調用它,但這不算在我的例子中。

感謝您的幫助。

更新: 我只想作出發言,下面所有的解決方案所做的工作對我來說不過來解決我的問題的解決方案通過提供巴里最簡單的方法。 Thx再次幫助我!

+1

你將不得不調用'fileStreamer.read ,性病::的unique_ptr>()'... – Jarod42

+0

你說得對,確實是我調用這個方法用錯了號碼的參數。在我提出正確的參數數量後,代碼編譯 – Bected

回答

1

的問題是,雖然我理解你的意圖:

std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>(); 

你實際上並沒有調用你認爲你的功能。你有read兩個重載:

template <class T> T read(); 
template <class T, 
    template<typename> class D, 
    template<typename, typename> class Container 
> T read(); 

第一個具有一個模板參數,第二個有3(和一些SFINAE)。但你只用一個模板參數調用read(),所以第二個重載 - 你想要的 - 甚至不是一個選項。

對於這些情況,我喜歡簡單的標記調度,使我們可以過載,而不必專門:

template <class T> struct tag{}; 

template <class T> T read() { return read(tag<T>{}); } 

template <class T> 
T read(tag<T>) { 
    T obj; 
    obj.readFromFile<T>(); 
    return obj; // <== NB: no move() here! That inhibits RVO 
} 

template <class T, class D> 
std::unique_ptr<T, D> read(tag<std::unique_ptr<T, D>>) { 
    /* unique_ptr case */ 
} 

+0

謝謝你的建議。該解決方案是解決我的問題的最簡單方法。哦,順便說一句,我使用std :: move,因爲我期望所有對象都應該有移動/分配構造函數。 – Bected

3

看來你想偏專業化,並在功能部分專業化是不可能的,你可以轉發類:

template <typename T> struct helper 
{ 
    T operator() const 
    { 
     T obj; 
     obj.readFromFile<T>(); 
     return obj; 
    } 
}; 

template <typename T, typename D> 
struct helper<std::unique_ptr<T, D>> 
{ 
    std::unique_ptr<T, D> operator() const 
    { 
     return std::make_unique<T, D>(readFromFile<T>()); 
    } 
}; 

template <typename T> 
T read() 
{ 
    return helper<T>{}(); 
} 
1
  1. 你不能有一個函數的兩個重載它只有返回類型不同。您必須使用SFINAE確保只有一個針對任何給定的模板參數啓用。
  2. 您嘗試在第二次重載中推導模板參數的方式是錯誤的。目前,您在調用函數時必須指定TDContainerType。我覺得你可能只想傳遞一種類型,然後推斷它是否爲std::unique_ptr
  3. 您不能撥打std::make_unique並指定刪除類型。您必須使用新創建的對象調用std::unique_ptr構造函數。
  4. 您不需要明確移動返回的std::unique_ptr

這是一種方法來做你想做的。

#include <memory> 
#include <type_traits> 

template<typename T> 
T readFromFile() { return T(); } 

template<typename T, typename D> 
void helper(std::unique_ptr<T, D>); 

template<typename T, typename = void> 
struct is_unique_ptr : std::false_type {}; 

template<typename T> 
struct is_unique_ptr<T, decltype(helper(std::declval<T>()))> : std::true_type {}; 

template<typename T, typename = std::enable_if_t<!is_unique_ptr<T>::value>> 
T read() 
{ 
    return readFromFile<T>(); 
} 

template<typename P, typename = std::enable_if_t<is_unique_ptr<P>::value>, typename = void> 
P read() 
{ 
    using T = typename P::element_type; 
    return P(new T(readFromFile<T>())); 
} 

int main() 
{ 
    read<std::unique_ptr<int>>(); 
    read<int>(); 
} 
相關問題