Кстати, проверил. Visual Studio 2010 тоже отвергает синтаксис operator+<size>. Она хочет просто operator+. Но при этом проект компилируется, но не собирается. Линкер не может найти этот самый operator+.

Пересоздал проект. Теперь не может и ряд методов класса найти. Перекомпилировал точно компилирующееся приложение - ошибка:
1>Link:
1> Generating code
1> Finished generating code
1>LINK : fatal error LNK1123: failure during conversion to COFF: file invalid or corrupt
Чушь какая-то.

Правда, у меня дома Windows 7 64 SP1, а студию я поставил для x86. На работе XP и студия тоже для x86. Может, в этом весь прикол. Как-то она криво работает.
Пишут, что такое случается, когда:
1)Вы запускаете VS 2010 после установки VS 2012.
2) Был установлен новый .Net Framework 4.5
3) Файлы .Net Framework 4 не в порядке (повреждены или удалены)
4) Файлы VS 2010 не в порядке.
Прикольно.
Возвращаясь к шаблонам. Всё-таки, как в QNX правильно и студия 2010 это приняла. Правда, иным образом.
Вот тут написано.
...
Если Вам кажется, что объявление в классе и определение вне его должны быть как-то связаны, то это не так. Это две совершенно разные функции(одна шаблонная, а другая нет), а т.к., согласно ADL(argument-dependent lookup), при вызове оператора, поиск надлежащей функции будет проведён в классе, то компилятор находит нашу friend-декларацию:
friend ostream& operator << (ostream &, const Matrix<int> &);
Но вот реализации этой декларации нет, отсюда и ошибка компоновщика.
...
Но теперь, в классе Matrix, мы добавим в друзья специализацию этого шаблона:
friend ostream& operator <<<T>(ostream & os, const Matrix & rhs);
friend istream& operator >><T>(istream &, Matrix &);
А так как мы объявляем другом специализацию, то мы должны вынести определение(или только объявление) общего шаблона до класса Matrix.
Однако, в этом случае операторы нужно вытащить выше определения класса (ну или там их предварительно описать). Иначе они не находятся компилятором.

И получается вот такой вот код:
#ifndef CMATRIX_H
#define CMATRIX_H
#include <math.h>
#include <string.h>
#include "cvector.h"
template<unsigned long size>
class CMatrix;
template<unsigned long size>
CMatrix<size> operator+(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right);//оператор "+"
template<unsigned long size>
CMatrix<size> operator-(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right);//оператор "-"
template<unsigned long size>
CMatrix<size> operator*(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right);//оператор "*"
template<unsigned long size>
CMatrix<size> operator*(const CMatrix<size>& cMatrix_Left,const double& value_right);//оператор "*"
template<unsigned long size>
CMatrix<size> operator*(const double& value_left,const CMatrix<size>& cMatrix_Right);//оператор "*"
template<unsigned long size>
CVector<size> operator*(const CMatrix<size> &cMatrix_Left,const CVector<size> &cVector_Right);//оператор "*"
template<unsigned long size>
CVector<size> operator*(const CVector<size> &cVector_Left,const CMatrix<size> &cMatrix_Right);//оператор "*"
//класс матрицы произвольной размерности
template<unsigned long size>
class CMatrix
{
private:
double *Item_Ptr;//указатель на массив компонентов матрицы
public:
CMatrix(void);//конструктор
~CMatrix(void);//деструктор
CMatrix(const CMatrix<size> &cMatrix);//конструктор копирования
double GetElement(unsigned long y,unsigned long x) const;//получить элемент матрицы
void SetElement(unsigned long y,unsigned long x,double value);//задать элемент матрицы
CMatrix<size>& operator=(const CMatrix<size>& cMatrix);//оператор "="
friend CMatrix<size> operator+<size>(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right);//оператор "+"
friend CMatrix<size> operator-<size>(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right);//оператор "-"
friend CMatrix<size> operator*<size>(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right);//оператор "*"
friend CMatrix<size> operator*<size>(const CMatrix<size>& cMatrix_Left,const double& value_right);//оператор "*"
friend CMatrix<size> operator*<size>(const double& value_left,const CMatrix<size>& cMatrix_Right);//оператор "*"
friend CVector<size> operator*<size>(const CMatrix<size> &cMatrix_Left,const CVector<size> &cVector_Right);//оператор "*"
friend CVector<size> operator*<size>(const CVector<size> &cVector_Left,const CMatrix<size> &cMatrix_Right);//оператор "*"
void Unitary(void);//привести к единичному виду
void Zero(void);//обнулить матрицу
};
//====================================================================================================
//конструктор
//====================================================================================================
template<unsigned long size>
CMatrix<size>::CMatrix(void)
{
Item_Ptr=new double[size*size+1];
}
//====================================================================================================
//деструктор
//====================================================================================================
template<unsigned long size>
CMatrix<size>::~CMatrix(void)
{
delete[](Item_Ptr);
}
//====================================================================================================
//конструктор копирования
//====================================================================================================
template<unsigned long size>
CMatrix<size>::CMatrix(const CMatrix<size> &cMatrix)
{
if (&cMatrix==this) return;
Item_Ptr=new double[size*size+1];
memcpy(Item_Ptr,cMatrix.Item_Ptr,size*size*sizeof(double));
}
//----------------------------------------------------------------------------------------------------
//получить элемент матрицы
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
double CMatrix<size>::GetElement(unsigned long y,unsigned long x) const
{
if (x>=size) return(0);
if (y>=size) return(0);
return(Item_Ptr[size*y+x]);
}
//----------------------------------------------------------------------------------------------------
//задать элемент матрицы
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
void CMatrix<size>::SetElement(unsigned long y,unsigned long x,double value)
{
if (x>=size) return;
if (y>=size) return;
Item_Ptr[size*y+x]=value;
}
//----------------------------------------------------------------------------------------------------
//оператор "="
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
CMatrix<size>& CMatrix<size>::operator=(const CMatrix<size> &cMatrix)
{
if (this!=&cMatrix)
{
memcpy(Item_Ptr,cMatrix.Item_Ptr,size*size*sizeof(double));
}
return(*this);
}
//----------------------------------------------------------------------------------------------------
//оператор "+"
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
CMatrix<size> operator+(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right)
{
CMatrix<size> cMatrix;
for(unsigned long y=0;y<size;y++)
{
for(unsigned long x=0;x<size;x++)
{
cMatrix.Item_Ptr[size*y+x]=cMatrix_Left.Item_Ptr[size*y+x]+cMatrix_Right.Item_Ptr[size*y+x];
}
}
return(cMatrix);
}
//----------------------------------------------------------------------------------------------------
//оператор "-"
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
CMatrix<size> operator-(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right)
{
CMatrix<size> cMatrix;
for(unsigned long y=0;y<size;y++)
{
for(unsigned long x=0;x<size;x++)
{
cMatrix.Item_Ptr[size*y+x]=cMatrix_Left.Item_Ptr[size*y+x]-cMatrix_Right.Item_Ptr[size*y+x];
}
}
return(cMatrix);
}
//----------------------------------------------------------------------------------------------------
//оператор "*"
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
CMatrix<size> operator*(const CMatrix<size>& cMatrix_Left,const CMatrix<size>& cMatrix_Right)
{
CMatrix<size> cMatrix;
double *m=cMatrix.Item_Ptr;
for(unsigned long y=0;y<size;y++)
{
double *m1_begin=&cMatrix_Left.Item_Ptr[y*size];
for(unsigned long x=0;x<size;x++,m++)
{
double s=0;
double *m2=&cMatrix_Right.Item_Ptr[x];
double *m1=m1_begin;
for(unsigned long n=0;n<size;n++,m1++,m2+=size) s+=(*m1)*(*m2);
*m=s;
}
}
return(cMatrix);
}
//----------------------------------------------------------------------------------------------------
//оператор "*"
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
CMatrix<size> operator*(const CMatrix<size>& cMatrix_Left,const double& value_right)
{
CMatrix<size> cMatrix;
for(unsigned long y=0;y<size;y++)
{
for(unsigned long x=0;x<size;x++)
{
cMatrix.Item_Ptr[size*y+x]=cMatrix_Left.Item_Ptr[size*y+x]*value_right;
}
}
return(cMatrix);
}
//----------------------------------------------------------------------------------------------------
//оператор "*"
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
CMatrix<size> operator*(const double& value_left,const CMatrix<size>& cMatrix_Right)
{
CMatrix<size> cMatrix;
for(unsigned long y=0;y<size;y++)
{
for(unsigned long x=0;x<size;x++)
{
cMatrix.Item_Ptr[size*y+x]=cMatrix_Right.Item_Ptr[size*y+x]*value_left;
}
}
return(cMatrix);
}
//----------------------------------------------------------------------------------------------------
//оператор "*"
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
CVector<size> operator*(const CMatrix<size> &cMatrix_Left,const CVector<size> &cVector_Right)
{
CVector<size> cVector;
//умножается строка на столбец
for(unsigned long y=0;y<size;y++)
{
double value=0;
for(unsigned long x=0;x<size;x++)
{
double m_value=cMatrix_Left.Item_Ptr[size*y+x];
double v_value=cVector_Right.GetElement(x);
value+=m_value*v_value;
}
cVector.SetElement(y,value);
}
return(cVector);
}
//----------------------------------------------------------------------------------------------------
//оператор "*"
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
CVector<size> operator*(const CVector<size> &cVector_Left,const CMatrix<size> &cMatrix_Right)
{
CVector<size> cVector;
//умножается строка на столбец
for(unsigned long x=0;x<size;x++)
{
double value=0;
for(unsigned long y=0;y<size;y++)
{
double m_value=cMatrix_Right.Item_Ptr[size*y+x];
double v_value=cVector_Left.GetElement(y);
value+=m_value*v_value;
}
cVector.SetElement(x,value);
}
return(cVector);
}
//----------------------------------------------------------------------------------------------------
//привести к единичному виду
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
void CMatrix<size>::Unitary(void)
{
unsigned long ptr=0;
for(unsigned long y=0;y<size;y++)
for(unsigned long x=0;x<size;x++,ptr++)
{
if (x==y) Item_Ptr[ptr]=1;
else Item_Ptr[ptr]=0;
}
}
//----------------------------------------------------------------------------------------------------
//обнулить матрицу
//----------------------------------------------------------------------------------------------------
template<unsigned long size>
void CMatrix<size>::Zero(void)
{
unsigned long ptr=0;
for(unsigned long y=0;y<size;y++)
for(unsigned long x=0;x<size;x++,ptr++)
{
Item_Ptr[ptr]=0;
}
}
#endif
Странно, правда, что в QNX не потребовалось делать предварительное описание.
