Вот скомпилированный пример, который я собрал из нескольких заголовочных файлов. Код не имеет смысла, потому что я потрошил все нерелевантные части, но суть в том, что я внедряю технику прокси данных Скотта Мейерса (упомянуто Вот), хотя он превратился в скорее в обертку, чем во временный прокси. Ничего из этого не должно иметь значения — мой вопрос, похоже, касается только различий в поведении компилятора.
#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 а также через CLion Jetbrain (набор инструментов: MinGW 3.20, CMake 2.8.12.2):
Однако он не скомпилируется на VS Express 2013:
Запустив полный код из CLion (который включает чтение CSV-файла чисел и вывод скользящего среднего), я могу убедиться, что вывод правильный. Просто 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];
это работает отлично. Есть идеи?
Похоже, это больше разбитости шаблона MSVC. Отказывается создавать экземпляр Proxy<double>
в этом коде, вызывая сбой разрешения перегрузки. Просто добавив Proxy<double> p;
прямо перед определением CRIXUS_MA
, что вызывает неявную реализацию, достаточно для компиляции кода. Согласно §14.7.1 [temp.inst] / p6:
Специализация шаблона класса неявно создается, если
Тип класса используется в контексте, который требует полностью определенного
тип объекта или если полнота типа класса может повлиять на
семантика программы. [ Заметка: В частности, если семантика
выражение зависит от списков членов или базовых классов класса
специализация шаблона, специализация шаблона класса
неявно генерируется. Например, удаление указателя на тип класса
зависит от того, объявляет ли класс деструктор, и
преобразование между указателями на типы классов зависит от наследования
отношения между двумя участвующими классами. —конечная нота ]
С семантикой sum += input[-j];
очевидно, зависит от определения Proxy<double>
, он должен был быть неявно создан.