2016-09-19 57 views
2

我有一個模板方法,返回類型將是reinterpret_cast <>()調用的結果。如何讓編譯器推斷C++ 11中模板化方法的返回類型?

class A { 
    void *_ptr; 
public: 
    template<typename T> 
    T buffer() { return reinterpret_cast<T>(_ptr); } 
}; 

這種方式讓我使用調用這個函數時<> -syntax:

A a; 
auto b = a.buffer<double *>(); 

我寧願不調用模板參數這種方法,讓編譯器推斷返回類型,基於在變量類型上。

A a; 
double *out = a.buffer(); 

這是可能的返回類型扣除?

我嘗試使用auto-> -operand和尾隨返回類型語法

auto buffer() -> decltype(reinterpret_cast<T>(_ptr)) const 
    { return reinterpret_cast<T>(_ptr); } 

但它仍然不起作用。

有沒有辦法做到這一點,在C + + 11?

+0

但可變類型是'A'。在代碼中沒有關於返回類型的信息。你必須在某個地方定義它,即。 '使用type = double;' –

+0

@ Jaa-c您能否詳細解釋您的澄清請求? –

回答

10

可以,但只能通過具有轉換功能模板代理類型:

struct BufferProxy { 
    void* ptr; 
    template<class T> operator T*() { return reinterpret_cast<T*>(ptr); } 
}; 
BufferProxy buffer() { return BufferProxy{_ptr}; } 

Example

需要注意的是誰已經熟悉了使用auto的返回類型推演用戶很可能通過這種技術變得混亂:

auto out = a.buffer(); // out is BufferProxy 
auto* out = a.buffer(); // fails to compile; can't deduce 'auto*' from 'a.A::buffer()' 

直到C++ 17,可以防止auto out = a.buffer();通過編譯給BufferProxy一個刪除的拷貝構造函數(也許通過集合構造返回它:return {_ptr};),但用戶仍然可以使用auto&&並從C++ 17 guaranteed copy elision將使auto表單再次工作。

+0

起首。確實是一個非常好的技巧。 +1 – skypjack

+0

對於一個高質量的答案,關於'auto'如何打破這個問題的說明會有所幫助,並且你可以做些什麼(即,讓'operator *'''&&'過載:不完美,但是會有所幫助。此外,你可以複製/移動私人(但停止幫助在C + + 17)和朋友的創建功能)。 – Yakk

0

你可能想要一個像下面這樣的類。這似乎提供了你想要做的大部分事情。

我想知道的一個問題是如何確定存儲到類中的指針是否是相同的類型。所以我認爲最好添加一個額外的方法來檢查使用hash_code()方法的typeid()

因此類,我想出了利用@ecatmur的operator想法在他/她的答案:

class A { 
    void *_ptr; 
    size_t _ptrHash; 

public: 
    template<typename T> operator T*() { return reinterpret_cast<T *>(_ptr); } 
    template<typename T> 
    void SetPtr(T *p) { _ptr = p; _ptrHash = typeid(*p).hash_code(); } 
    template<typename T> bool operator == (T *p) { return p && typeid(*p).hash_code() == _ptrHash /* && p == _ptr */; } 
}; 

等於運算符既可以只檢查的類型如上,或者如果您取消註釋額外的檢查,還要檢查指針的值。你可能只是想檢查類型。

,我用來測試了這一點,一個簡單的演示功能如下:

void funky1() { 
    A a; 

    double ddd[50] = { 0.0 }; 
    ddd[0] = 5.0; ddd[2] = 7.0; 

    a.SetPtr(&ddd[0]); 

    double *p = a; 
    bool bb = a == p; 

    long lll[50] = { 0 }; 
    lll[0] = 5; lll[2] = 7; 

    long *q = a; 
    bb = a == q; 

    a.SetPtr(&lll[0]); 
    q = a; 

    bb = a == q; 
} 

我通過這個加強與調試時,Visual Studio 2013,它看起來像它的工作就像一個冠軍。

0

我猜this answer是最優雅的。

無論如何,你也可以讓類,因爲它遵循初始化指針:

class A { 
    void *_ptr; 
public: 
    template<typename T> 
    void buffer(T **t) { *t = reinterpret_cast<T*>(_ptr); } 
}; 

int main() { 
    A a; 
    double *b; 
    a.buffer(&b); 
} 

這樣的類型從參數列表推導和你沒有顯式指定它。

相關問題