2009-10-29 31 views
0
// First try this: 

template <class T> T Read(istream& in) { 
    T t; 
    in >> t; 
    return t; 
} 

// If there is no operator>>(istream&, T) try this: 

template <class T> T Read(istream& in) { 
    return T (in); 
} 

// If there is no constructor T(istream&) try this: 

template <class T> T Read(istream& in) { 
    return T::OfStream (in); 
} 

// now fail. 

這可以實現嗎?C++編譯器可以嘗試不同的(模板T)實現,直到找到編譯(對於T)爲止?

如果不是,有什麼替代方案?

+0

你問:「可以這樣不違反現行標準的字母執行」,或「可以這樣從技術的角度來實現,忽視了標準說什麼是允許的?」 – 2009-10-29 02:27:18

+0

我都猜到了。在這種情況下,問題是:它的工作原理是什麼? – 2009-10-29 02:28:55

+0

Duplicate:http://stackoverflow.com/questions/257288/possible-for-c-template-to-check-for-a-functions-existence – 2009-10-29 05:37:59

回答

0

在符合標準的C++實現中,這些多歧義模板應該會產生一個錯誤(模糊由簽名定義,而不是由body定義)。我不知道任何違反標準的C++編譯器允許這些代碼(這並不意味着沒有足夠瘋狂的編譯器,只是我沒有聽說過這些;)。

1

如上所述,這些是不明確的。你應該看看增強enable_if或類似的,結合例如is_function

0

這不能按照您指定的方式直接執行,但有一種解決方法。可以定義模板轉換運算符,並且可以從預期的目標類型中推導出其類型參數。因此,你可以引入一個代理類:

class read_proxy 
{ 
public: 
    read_proxy(std::istream& in) : in(in) {} 
    template<class T> operator T() { T x; in >> x; return x; } 
private: 
    std::istream& in; 
}; 

read_proxy read(std::istream& in) 
{ 
    return read_proxy(in); 
} 

,然後用它作爲你本來想:

void foo(float) {} 

int main() 
{ 
    int x = read(std::cin); 
    foo(read(std::cin)); // float 
} 

這裏的潛在問題是,如果有人試圖堅持返回的代理本身,他可以運行轉化爲生存期的問題(因爲它擁有對流的簡單引用,並且後者可能在代理之前被破壞)。

8

您是否熟悉SFINAE的概念?使用這個概念,您可以根據模板參數的任何屬性從候選集中包含或排除函數模板。正如亞歷克斯·馬爾泰利所說,但是,你必須使這種情況發生在簽名中,而不是方法的主體。

這意味着您需要能夠對T類型的某些屬性進行編譯時決策,並使用該決策的結果強制模板簽名變爲非法,這會將該模板從編譯器的候選集合中排除而不會引起編譯錯誤。

Boost有兩個庫,可以方便這個:Boost.TypeTraits,它允許你問「像是一個數組?」的東西。或「是T指針?」或「是T的一個子類嗎?」在編譯時。該查詢的結果可以由Boost.EnableIf用於排除函數(或不按需要)。

您可能能夠在使用這些庫的組合後實現您的目標。如果您正在使用特定的編譯器,那麼您也可以使用特定於編譯器的擴展來獲得類似的結果(如果這對您有好處)。例如,使用MSVC,您可能可以使用__if_exists關鍵字。取決於你的簡單示例如何反映你真正想要做什麼,一種方法可能比另一種方法更清潔。

+0

那麼該怎麼做呢? 也就是說。如何檢查一個類是否已經命名構造函數OfStream? – 2009-10-29 12:20:37

+0

在上面的重複問題中,Nicola Bonelli提供了一個很好的例子。您可以使用Boost的BOOST_TYPEOF()宏來替換那裏使用編譯器特定的typeof()運算符,以提高可移植性。 – 2009-10-29 16:10:45

0

正如其他答案表明它不符合標準。

您沒有顯示預期的用法,因此有點難以弄清楚究竟是什麼,但您可以自己實現代碼(見下文),可以通過SFINAE進行更多改進以避免爲每個特定項創建轉換模板類:

#include <iostream> 
#include <sstream> 

using namespace std; 

struct A 
{ 
    int x; 
    A() : x(0) {} 
}; 

istream& operator>>(istream& in, A& a) 
{ 
    in >> a.x; 
    return in; 
} 

ostream& operator<<(ostream& on, A& a) { return on << "A: " << a.x; } 

struct B 
{ 
    int x; 
    B(istream& in) : x(0) { in >> x; } 
}; 

ostream& operator<<(ostream& on, B& b) { return on << "B: " << b.x; } 

struct C 
{ 
    int x; 
    C() : x(0) {} 

    static C OfStreamX(istream& in) 
    { 
     C c; 
     in >> c.x; 
     return c; 
    } 
}; 

ostream& operator<<(ostream& on, C& c) { return on << "C: " << c.x; } 

template <typename T> T Read(istream& in); 
template <> A Read(istream& in) 
{ 
    A a; 
    in >> a; 
    return a; 
} 

template <> B Read(istream& in) { return B(in); } 
template <> C Read(istream& in) { return C::OfStreamX(in); } 

int main() 
{ 
    string data("23 45 67"); 
    istringstream in(data); 

    A a = Read<A>(in); 
    cout << a << endl; 

    B b = Read<B>(in); 
    cout << b << endl; 

    C c = Read<C>(in); 
    cout << c << endl; 
} 

輸出:

A: 23 
B: 45 
C: 67 
相關問題