Я натолкнулся на реальную мозговую жару в C++, этого никогда не происходило со мной прежде.
Суть проблемы - то, что после вызова моего (шаблон) функционируют аргументы, для которых я определил значения по умолчанию, скремблировали их значения. Это только происходит, если я вызываю функцию со значениями по умолчанию.
Моя шаблонная функция объявляется как это:
template
vector2 transform(vector2 const &vec, matrix4 const &m, T z = T(0), T w = T(1));
Это позже, в том же заголовке, определенном как это:
template
inline vector2 transform(vector2 const &vec, matrix4 const &m, T z, T w)
{
vector4 res = m * vector4(vec.x, vec.y, z, w);
return vector2(res.x, res.y);
}
Теперь, когда я называю это со значениями по умолчанию (transform(vector2
) Я не получаю значения, которые я ожидаю. Продвижение в transform
с VC ++ s отладчик я вижу z
и w
наличие "забавных" значений (то, которое, по моему опыту, означает что-то, не инициализируется правильно).
Пример забавные значения был бы: 0.0078125000000000000 и 2.104431116947e-317#DEN
Теперь я попытался найти ответ на C++ FAQ Облегченный, гугля его; даже попробованный для успокаивания меня с Schubert но я не могу ни за что в жизни понять это. Я предполагаю, что это действительно просто, и я подозреваю, что это - некоторое шаблонное дурачество на работе.
Существует ли способ получить значения по умолчанию, которые я ожидаю и хочу, и почему он делает это мне?
Редактирование 1:
Если я вызов изменения, таким образом, это использует плавания вместо этого (transform(vector2
) проблема уходит. Кажется, что это только происходит если T
= double
.
Редактирование 2:
Это только происходит, если у меня есть две специализации для double
и float
. Если я использую специализацию плавающую в одном месте, двойная специализация становится странной значения по умолчанию. Если я изменяю все места, функция вызвана так, она использует дважды проблемы, "уходит". Я все еще не понимаю, почему, хотя, это похоже, это использует дефектные смещения или что-то при установке z
и w
.
Редактирование 3:
Рассказы от склепа C++:
#include
int main(int argc, char *argv[])
{
sgt::matrix4 m0(
2, 0, 0, 1,
0, 2, 0, 1,
0, 0, 1, 0,
0, 0, 0, 1);
m0 *= m0;
sgt::vector2 blah0 = sgt::transform(sgt::vector2(1, 0), m0);
sgt::matrix4 m1(
2, 0, 0, 1,
0, 2, 0, 1,
0, 0, 1, 0,
0, 0, 0, 1);
m1 *= m1;
sgt::vector2 blah1 = sgt::transform(sgt::vector2(1, 0), m1);
printf("%f", blah0.x);
printf("%f", blah1.x);
}
В matrix4.hpp:
// ...
template
vector2 transform(vector2 const &vec, matrix4 const &m, T z = T(0), T w = T(1));
template
inline vector2 transform(vector2 const &vec, matrix4 const &m, T z, T w)
{
vector4 res = m * vector4(vec.x, vec.y, z, w);
return vector2(res.x, res.y);
}
// ...
Если я выполняю это, двойная специализация имеет, это - корректные параметры по умолчанию, но версия плавающая получает обоих, которые это - параметры по умолчанию как нуль (0.000000), который, хотя лучше, это все еще, не является z = 0
и w = 1
.
Редактирование 4:
Сделанный проблемой Подключения.
У меня в Dev Studio не работает:
#include "stdafx.h"
#include <vector>
#include <iostream>
template <typename T>
std::vector<std::vector<T> > transform(std::vector<std::vector<T> > const &vec,
std::vector<std::vector<std::vector<std::vector<T> > > > const &m,
T z = T(0), T w = T(1));
template <typename T>
std::vector<std::vector<T> > transform(std::vector<std::vector<T> > const &vec,
std::vector<std::vector<std::vector<std::vector<T> > > > const &m,
T z, T w)
{
std::cout << "Z" << z << "\n";
std::cout << "W" << w << "\n";
return vec;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<std::vector<int> > xi;
std::vector<std::vector<std::vector<std::vector<int> > > > mi;
transform(xi,mi);
std::vector<std::vector<float> > xf;
std::vector<std::vector<std::vector<std::vector<float> > > > mf;
transform(xf,mf);
std::vector<std::vector<double> > xd;
std::vector<std::vector<std::vector<std::vector<double> > > > md;
transform(xd,md);
}
Output:
Z0
W1
Z0
W1.4013e-045
Z2.122e-314
W3.60689e-305
Так что я полагаю, что это не работает так, как ожидалось!!!
Если убрать предварительное объявление и поместить аргументы по умолчанию в функцию шаблона, то все работает как ожидалось.
#include "stdafx.h"
#include <vector>
#include <iostream>
template <typename T>
std::vector<std::vector<T> > transform(std::vector<std::vector<T> > const &vec,
std::vector<std::vector<std::vector<std::vector<T> > > > const &m
T z = T(0), T w = T(1))
{
std::cout << "Z" << z << "\n";
std::cout << "W" << w << "\n";
return vec;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::vector<std::vector<int> > xi;
std::vector<std::vector<std::vector<std::vector<int> > > > mi;
transform(xi,mi);
std::vector<std::vector<float> > xf;
std::vector<std::vector<std::vector<std::vector<float> > > > mf;
transform(xf,mf);
std::vector<std::vector<double> > xd;
std::vector<std::vector<std::vector<std::vector<double> > > > md;
transform(xd,md);
}
Это работает как ожидалось.
Это связано с тем, что предварительная декларация шаблона на самом деле не является предварительной декларацией функции, и поэтому у нее нет параметров по умолчанию, и поэтому вы получаете случайные значения в списке параметров.
OK. Из моего чтения стандарта следует, что это должно работать как ожидалось:
Используя n2521
Раздел 14.7.1 Неявное инстанцирование
Параграф 9
Реализация не должна неявно инстанцировать шаблон функции, шаблон члена, невиртуальную функцию-член, класс-член или статический член данных шаблона класса, который не требует инстанцирования. Не определено, должна ли реализация неявно инстанцировать виртуальную функцию-член шаблона класса, если иначе эта виртуальная функция-член не была бы инстанцирована. Использование специализации шаблона в аргументе по умолчанию не должно приводить к неявному инстанцированию шаблона, за исключением того, что шаблон класса может быть инстанцирован, если его полный тип необходим для определения корректности аргумента по умолчанию. Использование аргумента по умолчанию в вызове функции приводит к неявному инстанцированию специализаций в аргументе по умолчанию.
Выделенная жирным часть параграфа, как мне кажется, указывает на то, что каждая специализация, созданная из-за аргументов по умолчанию, будет неявно инстанцирована в единицу перевода при использовании.
Параграф 11:
Если шаблон функции f вызывается таким образом, что требуется использовать выражение аргумента по умолчанию, то просматриваются зависимые имена, проверяются ограничения семантики, и инстанцирование любого шаблона, используемого в выражении аргумента по умолчанию, выполняется так, как если бы выражение аргумента по умолчанию было выражением, используемым в специализации шаблона функции с той же областью видимости, теми же параметрами шаблона и тем же доступом, что и у шаблона функции f, используемого в этот момент. Этот анализ называется инстанцированием аргумента по умолчанию. Инстанцированный аргумент по умолчанию затем используется в качестве аргумента функции f.
Указывает, что даже если аргументы по умолчанию являются параметрами шаблона, они будут правильно инстанцированы.
Надеюсь, я правильно это интерпретировал :-)
.Я не знаю, сработает ли это, но попробуйте использовать static_cast вместо преобразования стиля C для значений по умолчанию.
* Edit: Видимо проблема в компиляторе.
Оптимизирован ли код? Может быть, поэтому отладчик показывает неправильные значения.
Я пробовал этот более простой код (в g ++ 4.3.3), и он работает, как ожидалось.
template <typename T>
T increment(T a, T b = T(1))
{
return a + b;
}
int main()
{
double a = 5.0;
std::cout << increment(a) << ", ";
std::cout << increment(a, 3.0) << "\n";
}