3

下面是我從幾個頭文件拼接在一起的可編譯示例。代碼沒有意義,因爲我解開了所有不相關的部分,但要點是我正在實施Scott Meyers的數據代理技術(提到here),儘管它演變成更多的包裝而不是臨時代理。這些都不重要,但我的問題似乎純粹是關於編譯器行爲的差異。爲什麼不在VS Express 2013中編譯,儘管它在MinGW中編譯?

#include <iostream> 
#include <vector> 

template<typename T> 
class Proxy 
{ 
public: 
    enum class State 
    { 
     NEVER_SET = 0, 
     SET, 
     UNSET 
    }; 
    operator const T&() const 
    { 
     if (_state != State::SET) 
     { 
      std::cout << "EXCEPTION" << std::endl; 
      // TODO throw exception 
     } 
     return _data; 
    } 
    Proxy<T>& operator=(const T& val) 
    { 
     _data = val; 
     _state = State::SET; 
     return (*this); 
    } 
    Proxy<T>& operator+=(const T& val) 
    { 
     _data = (*this) + val; 
     _state = State::SET; 
     return (*this); 
    } 
private: 
    T _data; 
    State _state = State::NEVER_SET; 
}; 

class Tape 
{ 
}; 

template<typename T> 
class tape : public Tape 
{ 
public: 
    const Proxy<T>& operator[](int idx) const 
    { 
     return operator[](idx); 
    } 
    Proxy<T>& operator[](int idx) 
    { 
     if (idx >= data.size()) 
     { 
      data.resize(idx + 1); 
     } 
     return data[idx]; 
    } 
private: 
    std::vector< Proxy<T> > data; 
}; 

class CRIXUS 
{ 
public: 
    virtual void Go() final {}; 
protected: 
    virtual void Pre() {}; 
    virtual void Post() {}; 
    virtual void Step() = 0; 
}; 

class CRIXUS_MA : public CRIXUS 
{ 
public: 
    int window = 30; 
    tape<double> input; 
    tape<double> output; 
protected: 
    virtual void Step() 
    { 
     double sum = 0; 
     for (int j = 0; j < window; j++) 
     { 
      sum += input[-j]; 
     } 
     output[0] = sum/window; 
    } 
}; 

int main() 
{ 
} 

它編譯罰款Ideone,以及通過Jetbrain的克利翁(工具鏈:MinGW的3.20,CMake的2.8.12.2):

enter image description here

但是它不會在VS 2013快編譯:

enter image description here

運行從克利翁完整代碼(包括讀取NUM的.csv文件並輸出移動平均線),我可以驗證輸出是否正確。這只是VS不會編譯代碼。

據我所知,中投操作

operator const T&() const 
    { 
     if (_state != State::SET) 
     { 
      std::cout << "EXCEPTION" << std::endl; 
      // TODO throw exception 
     } 
     return _data; 
    } 

應該轉換Proxy<T>TProxy<double>double。當我強行施放違規線時,

 sum += (double)input[-j]; 

它工作正常。有任何想法嗎?

+0

哪條線是86線? – 2014-09-02 05:58:24

+0

唉,對不起。這是'sum + = input [-j];'。在那裏,'input [-j]'應該返回'Proxy ',但由於'sum'是'double',我預計會發生轉換。 – 2014-09-02 05:59:11

+0

你能減少一個最小的例子嗎? (儘可能多地拿出,但仍然有問題發生) – 2014-09-02 05:59:55

回答

4

這似乎是更多的MSVC模板碎片。它拒絕在此代碼中實例化Proxy<double>,導致重載解析失敗。在CRIXUS_MA的定義之前簡單地添加一個Proxy<double> p;(強制隱式實例化)就足以使代碼編譯。根據§14.7.1[temp.inst]/P6:

如果 類的類型在需要完全定義 對象類型的上下文,或者如果完整性中使用的類模板特被隱式地實例化類的類型可能會影響程序的語義。 [注意:特別是,如果 表達式的語義取決於類別 模板專用化的成員或基類列表,則隱含地生成類模板專用化 。例如,刪除指向類類型 的指針取決於該類是否聲明析構函數,並且指向類類型的指針之間的轉換取決於涉及的兩個類之間的關係 。 - 注完]

由於sum += input[-j];語義顯然取決於Proxy<double>定義的,它應該被隱式實例。

+0

謝謝;我剛剛根據你的建議發佈了這個消息,我添加了'Proxy dummy'作爲'class tape'的成員,並且工作正常。 (我不希望手動指定'double'和其他原語。)然而,關於成員和非成員操作符的評論看起來非常引人注目。你認爲他們與這個問題有關嗎?或者只是貌似。 (我問你,因爲我覺得沒有足夠的經驗來判斷。) – 2014-09-02 06:26:37

+1

@AndrewCheong這與你遇到的問題無關。大量標準庫類型將'operator + ='定義爲類成員。 – 2014-09-02 06:29:51