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 в CLion (Toolchain: MinGW 3.20 CMake 2.8.12.2):

enter image description here

Однако он не будет компилировать на VS Express, 2013:

enter image description here

Запуск полный код из CLion (который включает в себя чтение CSV-файл NUM и вывод скользящего среднего), я могу проверить правильность вывода. Просто VS не будет компилировать код.

Насколько я могу судить, оператор приведения

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

должен преобразовать Proxy<T> в T, т.е.Proxy<double> к double. И когда я принудительно лишаю линию нарушения,

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

это прекрасно работает. Есть идеи?

+0

Какая линия линии 86? –

+0

Agh, извините. Это 'sum + = input [-j];'.Там 'input [-j]' должен возвращать 'Proxy ', но поскольку 'sum' является' double', я ожидаю, что произойдет конверсия. –

+0

Можете ли вы привести к минимальному примеру? (вытащите столько, сколько сможете, но все еще есть проблема) –

ответ

4

Это, по-видимому, больше нарушает шаблон MSVC. Он отказывается создавать код Proxy<double> в этом коде, что приводит к сбою разрешения перегрузки. Просто добавив Proxy<double> p; прямо перед определением CRIXUS_MA, которое заставляет неявное создание экземпляра, достаточно сделать компиляцию кода. Согласно §14.7.1 [temp.inst]/p6:

Шаблона класса специализация неявно реализованной, если тип класса используется в контексте, который требует совершенно определенного типа объект или если полноты типа класса может повлиять на семантику программы . [Примечание: В частности, если семантика выражение зависит от списков членов или базового класса для специализированной специализации класса , специализация шаблона класса составляет , неявно сгенерированную. Например, удаление указателя на тип класса зависит от того, объявляет ли класс деструктор или нет, и преобразование между указателями на типы классов зависит от взаимосвязи между двумя классами наследования . - конец примечание]

Поскольку семантика sum += input[-j];, очевидно, зависит от определения Proxy<double>, оно должно было быть неявно экземпляр.

+0

Thanks; Я как раз собирался опубликовать это на основании вашего предложения, я добавил 'Proxy dummy' в качестве члена' class tape', и это сработало. (Я не хотел указывать «двойные» и другие примитивы вручную). Однако комментарии относительно операторов-членов и не-членов выглядели действительно убедительными. Считаете ли вы, что они имеют отношение к этой проблеме? Или только по-видимому. (Я прошу вас, потому что я не чувствую себя достаточно опытным, чтобы судить.) –

+1

@AndrewCheong Это не относится к проблеме, которую вы испытываете. Множество стандартных типов библиотек определяют 'operator + =' как членов класса. –