2015-10-01 108 views
5

假設下面的代碼片段:給nullptr一個類型模板扣除

template <class T> 
void fct(T* a, T* b){ 
    // do something 
} 

A a; 
fct(&a, nullptr); // Problem here! 

這使得麻煩,因爲調用的參數是A*類型和nullptr_t所以編譯器不能推斷出模板參數T

一般情況下,我可以想像幾個想法如何解決這個問題:

  • 定義A* b = nullptr和使用fct(&a, b)
  • 定義過載與一個參數爲fctnullptr情況
  • 使用fct(&a, static_cast<A*>(nullptr))

還是有一個更乾淨的解決方案,麗創建類似於「類型化nullptr」的東西?

+0

你想要的「類型nullptr」可能與'static_cast (nullptr)'不同嗎? – Petr

+2

你的第二個選擇看起來像最好的選擇...重載(模板專業化) – basav

+0

你已經在回答問題了......第一和第三選擇或多或少是相同的:你需要一個T *而nullptr不是你不允許的' fct(&a,nullptr)',第二個使用顯式重載來允許它。我無法想象另一個答案... –

回答

2

我也建議以下解決方案:

template <class T, class U> 
void fct(T* a, U b){ 
    T* b2 = b; 
    // do something 
} 

A a; 
fct(&a, nullptr); 

這允許fct一個更廣泛的使用,但也許這正是你想要的東西。

例如,考慮

class A {}; 
class B : public A {}; 

... 
A a; 
B b; 
fct(&a, &b); // calls fct<A> 
// the following will not compile: 
// fct(&b, &a); 
1

您可以使用下面的代碼:

#include <type_traits> 

template<class T> 
void f_impl(T*, T*) 
{ 
    std::cout << typeid(T).name() << "\n"; 
} 


template<class T, class U> 
void f(T l, U r) 
{ 
    static_assert((std::is_same<T, U>::value && std::is_pointer<T>::value) || 
        (std::is_same<T, std::nullptr_t>::value && std::is_pointer<U>::value) || // First non-null 
        (std::is_same<U, std::nullptr_t>::value && std::is_pointer<T>::value) // Second non-null 
        , ""); 

    using P = typename std::conditional<std::is_same<T, std::nullptr_t>::value, U, T>::type; 

    f_impl<typename std::remove_pointer<P>::type>(l, r); 
} 

int main() 
{ 
    int i; 
    f(&i, nullptr); 
    f(nullptr, &i); 
    // f(i, nullptr); // won't compile - non-pointer 
    f(&i, &i); 

    double d; 
    // f(&i, &d); // - won't compile 

} 

這個版本測試將允許調用f一個nullptr(但不能同時),或者用兩個指針到相同的類型。使用C++ 14,您還可以使用諸如std::conditional_t,std::remove_pointer_tstd::is_null_pointer之類的東西來刪除某些生物盤。

+0

您需要調用'f '或'f ',具體取決於哪個非空;當你調用'f(nullptr,&i)'時,你當前的版本調用'f '。 – Petr

+0

@Petr該代碼存在更多問題。修正它們。謝謝! – Rostislav

5

只是要第二個參數非推斷背景下,e.g:

template <class T> 
void fct(T* a, std::remove_reference<T*>::type b) { 
+0

在第二個函數參數前面缺少'typename'?人們也可以使用更新的,略少詳細的'std :: remove_reference_t'。 – user1735003

0

由於問題已經指出,nullptr其實都有一個類型:std::nullptr_t。所以,只需要加一個明確的重載明確的話:

template <class T> 
void fct(T* a, std::nullptr_t b) { return fct<T>(a,static_cast<T*>(b)); } 

無需有一些爲模板參數class U