2014-10-06 34 views
2

考慮以下系統:禁用默認模板,並且只使用專門通過SFINAE

template<typename T> 
    struct wrapper 
    { 
     operator T *() { return nullptr; } 
    }; 

template<typename Ret, typename T> 
    Ret func(T); 

template<> 
    int func(float * in) 
    { 
     std::cout << "long"; 
    } 

template<> 
    long func(float * in) 
    { 
     std::cout << "int"; 
    } 

包裝的目的是允許它衰減到它的模板的類型(它是圍繞一個緩衝包裝類型)。此外,我有一套功能模板的模板專業化。這是爲了避免僅基於返回類型重載時的常見錯誤。

這不工作,雖然,如前所述這裏:相反

// the following should work, but doesn't because it's instantiating 
// the func<ret, wrapper<float>> which doesn't exist resulting in a linker error 
// instead of selecting the int func(float *) overload 
wrapper<float> w; 
func<int>(w); 

,我想這生成編譯時錯誤(但同樣,它生成一個鏈接時錯誤):

// the following should generate a compile-time error 
// since no explicit overload for int func(int *) exists 
wrapper<int> w2; 
func<int>(w2); 

所以理想情況下,我想禁用原始模板(如果可能的話可以通過sfinae?),這樣重載決議只考慮明確的特化,並且如果沒有找到匹配就會產生編譯時錯誤。這可以做到嗎?

鏗鏘和msvc之間的便攜式解決方案是必須的,但我使用兩者的最新版本。

+1

您的問題,還不如說是模板參數推導,不考慮隱式轉換儘可能多的重載決議。 – 2014-10-06 16:04:02

+0

@ P0W因爲你不能超載這兩個。唯一的區別是返回類型。 – 2014-10-06 16:14:17

+0

@TC Ahh我看到了,謝謝 – P0W 2014-10-06 16:15:25

回答

1

如果你

template<typename Ret> Ret func(float*); 

它按預期工作:Live example

+0

感謝您的想法 - 這是解決方案的一部分(請參閱我的回答) – Shaggi 2014-10-06 18:45:00

1

雖然賈羅德的回答解決的問題之一,我仍然需要一種方法來重載函數的參數(在這種情況下,會產生'沒有匹配模板'的錯誤) - 我可能沒有在OP中說明。

在我看來,參數類型總是依賴於返回類型。然後,我可以建立一個輔助性結構,即會做SFINAE:

template<typename T> 
    struct option_of; 

template<> 
    struct option_of<int> 
    { 
     typedef float value; 
    }; 

template<> 
    struct option_of<long> 
    { 
     typedef double value; 
    }; 

,然後默認的模板應該是這樣的:

template<typename Ret> 
    Ret func(typename const option_of<Ret>::value *); 

,然後重載可以構建這樣的:

template<> 
    int func(const float * in) 
    { 
     std::cout << "long"; 
    } 

template<> 
    long func(const double * in) 
    { 
     std::cout << "int"; 
    } 

- 沒有問題。請注意,任何其他組合的返回和參數類型都是無效的(因爲它們不是原始模板的專門化,只考慮我給出的選項)。這也降低了僅過載分辨率的兩個過載,並因此使這成爲可能:

wrapper<float> w; 
func<int>(w); // works 
func<long>(w); // invalid, because no combination of long and float exists according to option_of 

wrapper<int> w2; // works, but 
func<int>(w2); // invalid because option_of doesn't consider int's 

課程的額外的好處是編譯器可以識別在呼叫/實例化與正確的錯誤消息的錯誤,而不是一些隨機static_assert /鏈接器錯誤。成功!

+0

在您的示例中,參數不僅取決於返回類型,還有其他解決方法。如果您創建了return_of :: value,那麼您的模板參數可以是隱式的,您可以在不使用模板參數的情況下調用func(w2)。 – sluki 2015-07-03 10:43:18

1

另一種方法可以是使用static_assert:

template<typename Ret, typename T> 
Ret func(T) { 
    static_assert(false, "template specialization required"); 
}