2013-04-09 106 views
36

我想專用一個函數模板,以便返回類型根據模板參數的類型而變化。覆蓋函數模板專門化中的返回類型

class ReturnTypeSpecialization 
{ 
public: 
    template<typename T> 
    T Item(); 
}; 

// Normally just return the template type 
template<typename T> 
T ReturnTypeSpecialization::Item() { ... } 

// When a float is specified, return an int 
// This doesn't work: 
template<float> 
int ReturnTypeSpecialization::Item() { ... } 

這可能嗎?我無法使用C++ 11。

+0

你想達到什麼目的? – didierc 2013-04-09 20:37:52

+0

我想要一個函數來返回作爲模板參數提供的類型,除非在特殊情況下我希望函數返回不同的類型。 – 2013-04-09 20:40:51

+0

只是爲了記錄:如果模板參數是從參數的類型中推導出來的,而不是明確指定的,則完成返回不同類型的更簡單的方法是使用函數重載。 (當然這個例子在這個例子中不起作用,因爲沒有參數) – jorgbrown 2017-05-09 16:03:41

回答

38

由於專業化與返回類型的基本模板的同意,你可以通過添加一個「返回類型特徵」做起來很,一個結構,你可以專注並從中汲取真正的返回類型:

// in the normal case, just the identity 
template<class T> 
struct item_return{ typedef T type; }; 

template<class T> 
typename item_return<T>::type item(); 

template<> 
struct item_return<float>{ typedef int type; }; 
template<> 
int item<float>(); 

Live example.

請注意,你可能要堅持以下,所以你只需要更新的返回類型在item_return專業化。

template<> 
item_return<float>::type foo<float>(){ ... } 
// note: No `typename` needed, because `float` is not a dependent type 
+1

+1我喜歡這個:P – Rapptz 2013-04-09 20:51:10

+2

確保所有的特化都在它們被實例化之前被聲明。實際上,這意味着專業化必須在同一個頭文件中聲明,並且聲明應該儘可能地接近。 – aschepler 2013-04-09 20:55:31

+0

@aschepler:非常好的一點。擺弄這種形式的專業化非常不穩定。 – Xeo 2013-04-09 20:57:36

4

你可以做模板特像這樣:

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

template<> 
float item<float>() { 
    return 1.0f; 
} 
+2

這意味着'T'也是總是返回類型,從問題的例子來看,似乎並不是這種情況。 – Xeo 2013-04-09 20:33:50

+0

@Zeta:你可以完全專注於它們(也稱爲* explicit specialization *)。 – Xeo 2013-04-09 20:34:33

+0

@Xeo:問題標題:*「 覆蓋功能模板專業化中的返回類型 」*。可能是問題內容中的拼寫錯誤。 – Zeta 2013-04-09 20:34:59

4

也許你可以使用下面的技巧。鑑於這些簡單的類型特點:

template<bool b, typename T, typename U> 
struct conditional { typedef T type; }; 

template<typename T, typename U> 
struct conditional<false, T, U> { typedef U type; }; 

template<typename T, typename U> 
struct is_same { static const bool value = false; }; 

template<typename T> 
struct is_same<T, T> { static const bool value = true; }; 

你可以寫出如下類和專業的成員函數:

class ReturnTypeSpecialization 
{ 
public: 
    template<typename T> 
    typename conditional<is_same<T, float>::value, int, T>::type 
    Item(); 
}; 

// Normally just return the template type 
template<typename T> 
typename conditional<is_same<T, float>::value, int, T>::type 
ReturnTypeSpecialization::Item() { return T(); } 

// When a float is specified, return an int 
template<> 
int ReturnTypeSpecialization::Item<float>() { return 1.0f; } 

簡單的測試程序(使用C++ 11只是爲了驗證):

int main() 
{ 
    ReturnTypeSpecialization obj; 
    static_assert(std::is_same<decltype(obj.Item<bool>()), bool>::value, "!"); 
    static_assert(std::is_same<decltype(obj.Item<float>()), int>::value, "!"); 
} 

這是live example

+0

他沒有C++ 11。 – Rapptz 2013-04-09 20:47:50

+0

@Rapptz:好的,對不起,我錯過了。但我相信這可以重寫,而不使用任何C++ 11功能('std :: conditional'不難重寫) – 2013-04-09 20:49:31

+0

我認爲你的錯誤處理方式是錯誤的。此外,這是一個很好的模板,可以擴展到更多的專業領域,更糟糕的是,所有的專業領域都必須事先知道。 – Xeo 2013-04-09 20:54:21

2

做一個工人類的所有專業化,並使用一個簡單的函數作爲包裝將隱含專門化。

#include <iostream> 
using std::cout; 

// worker class -- return a reference to the given value 
template< typename V > struct worker 
    { 
    typedef V const & type; 
    static type get(V const & v) { return v; } 
    }; 

// worker class specialization -- convert 'unsigned char' to 'int' 
template<> struct worker<unsigned char> 
    { 
    typedef int type; 
    static type get(unsigned char const & v) { return v; } 
    }; 

// mapper function 
template< typename V > typename worker<V>::type mapper(V const & v) 
    { 
    return worker<V>::get(v); 
    } 

int main() 
    { 
    char a='A'; 
    unsigned char b='B'; 
    cout << "a=" << mapper(a) << ", b=" << mapper(b) << "\n"; 
    } 

在這個例子中,unsigned char專業化導致它被轉換爲int,使得cout將其顯示爲一個數而不是作爲一個字符,產生以下輸出...

a=A, b=66 
+0

這與@ Xeo的答案具有相同的基本機制,但由於只需要一個專業化,所以可能會被認爲有點清潔。實施的另一個特點是,正常情況基本上是一個NOP - 它只是返回一個對原始值的引用。 – nobar 2014-01-23 05:27:25

+0

我也喜歡這個解決方案。如果你想特別禁止通用的解決方案,只允許顯式模板,第一個結構可以改變爲'template struct worker;',沒有主體。 – Eyal 2017-12-19 07:39:18