C++ (по-конкретно, реализацията на g++ на MinGW) се обърква. Имам математически векторен клас, който съдържа произволен номер от произволен тип елемент. Типът на елемента и броят на елементите се определят по време на компилиране.
Класът Vector се обърква между един от неговите конструктори и това, което нарекох оператор "преоразмеряване". Операторът за преоразмеряване позволява на програмиста да преобразува вектор с един размер във вектор с друг произволен размер. Ако кастинг векторът има повече елементи от базовия вектор, той се допълва с 1. Ето изпълнението:
/*
* resize operator:
* T is the type of element the base vector holds
* N is the number of elements the base vector holds
* rN is the size of the new vector
*/
template<typename T, unsigned int N, unsigned int rN>
operator Vector<T, rN>() const
{
Vector<T, rN> resize;
for (unsigned int i = 0; i < rN; i++)
{
resize[i] = i < N ? this->elements[i] : 1;
}
return resize;
}
Векторният клас също така има безопасен за тип променлив конструктор, който може да приема произволен брой всякакви комбинации от елементи (които трябва да са от тип T) и произволен брой вектори (които могат да съдържат произволен брой елементи и трябва да бъдат от тип T), така че стига броят на голите елементи, добавени към броя на елементите в предоставените вектори, да е равен на броя на елементите, които съставящият вектор съдържа.
Следователно това би било валидно:
vec3 foo(vec2(1, 2), 3);
но не и това.
vec3 bar(vec4(1, 2, 3, 4), 5);
Гарантирам, че правилният брой елементи е бил доставен по време на компилиране, като рекурсирам през всички тях с брояч, след което използвам статично твърдение, за да се уверя, че броячът завършва на броя елементи, които векторът може да съдържа. Това обикновено работи добре, с изключение на следния код:
vec4 bar(1, 2, 3, 4);
(vec3) bar; //PROBLEM HERE
Това, което се случва, е, че C++ смята, че лентата (vec3) изисква променлив конструктор, когато всъщност трябва да извиква оператора за преоразмеряване. Опитах се да ги направя изрични, но не се получи. Как да гарантирам, че C++ използва оператора за преоразмеряване, когато имам горния код, а не променливия конструктор?
Накратко, как да кажа на C++ да използва това:
//resize operator
template<typename T, unsigned int N, unsigned int rN>
Vector<T, N>::operator Vector<T, rN>();
вместо това:
//constructor
template<typename T, unsigned int N, typename ... Args>
Vector<T, N>::Vector(Args ... arguments);
когато имам този код:
(vec3) someVec4;
В случай, че не е ясно, vec3 и vec4 се дефинират като такива:
typedef Vector<float, 3> vec3;
typedef Vector<float, 4> vec4;
РЕДАКТИРАНЕ:
Новини, всички! Дори когато използвам static_cast(someVec4), той все още извиква конструктора vec3 с аргумент vec4. Не знам защо.
ДРУГА РЕДАКЦИЯ:
Правенето на конструктора изричен позволява неявните преобразувания да работят, но не и изричните. Което означава, че този код работи:
vec3 foo = someVec4;
Но този код все още ми дава грешка при статично твърдение:
vec3 foo = static_cast<vec3>(someVec4);
Което по принцип няма смисъл, защото декларирах variadic конструктора изричен и следователно той не трябва да се извиква там.
Освен това, при поискване, ето SSCCE
Версията TL;DR на това е, че моят код извиква явен конструктор, когато се опитвам изрично да извикам оператора за преобразуване на типове, но не и когато се опитвам да го извикам имплицитно.
explicit
? - person aschepler   schedule 11.08.2012