LINUX.ORG.RU

Перегрузка операций

 ,


0

3

Есть такой вот класс

#include <iostream>

template <int D, typename T=double> class Vec{
        T p[D];

        inline void set_x(){}
        template <typename T2, typename ... Args>
        inline void set_x(const T2& x, const Args&... xxx){     p[D-1-sizeof...(Args)] = x; set_x(xxx...); }
public:
        explicit Vec(T val=0) { for(int i=0; i<D; i++) p[i] = val; }    
        Vec(const Vec<1, T> &v){ for(int i=0; i<D; i++) p[i] = v[0]; }
        template <class T2> /* explicit ??? */ Vec(const Vec<D, T2> &v){ for(int i=0; i<D; i++) p[i] = v[i]; }

        template <typename ... Args> explicit Vec(const Args&... xxx){ 
                static_assert(sizeof...(Args)==D, "illegal parametrs count!"); 
                        set_x(xxx...); 
        }
        template <class T2> inline Vec& operator = (const Vec<D,T2> &v){ 
                for(int i=0; i<D; i++) p[i] = v[i]; 
                return *this; 
        }

        inline T& operator [] (int i){ return p[i]; } 
        inline T operator [] (int i) const { return p[i]; } 
};

template <int D, typename T1, typename T2>
inline Vec<D, decltype(T1()+T2())>  operator + (const Vec<D,T1> &a, const Vec<D,T2> &b){
        Vec<D, decltype(T1()+T2())> r;
        for(int i=0; i<D; i++) r[i] = a[i]+b[i];
        return r;
}

template <int D, typename T> std::ostream& operator << (std::ostream &s, const Vec<D, T> &v){
        s<<"Vec<"<<D<<",szT="<<sizeof(T)<<">:";
        if(D) s<<v[0]; for(int i=1; i<D; i++) s<<" "<<v[i]; return s;
}

template <typename T, typename ... Args>
inline Vec<1+sizeof...(Args), T> vec(T x, Args ... args){
        return Vec<1+sizeof...(Args), T>(x, args...);
}

int main(){
        Vec<3, int> x(7,2,3);
        Vec<3> y(1.);
        std::cout<<(x+y)<<std::endl;
        std::cout<<(vec(1)+x)<<std::endl; // <<< тут проблема
}

Хочется что бы поддерживались операции вида

Vec<D,T1>+Vec<D,T2>
Vec<1,T1>+Vec<D,T2>
Vec<D,T1>+Vec<1,T2>
но два вторых типа не работают, почему то не срабатывает конструктор
        Vec(const Vec<1, T> &v){ for(int i=0; i<D; i++) p[i] = v[0]; }
говорит
$ g++ -Wall -O3 -std=c++11 test.cpp
test.cpp: In function ‘int main()’:
test.cpp:49:20: error: no match for ‘operator+’ (operand types are ‘Vec<1, int>’ and ‘Vec<3, int>’)
  std::cout<<(vec(1)+x)<<std::endl;
                    ^
test.cpp:49:20: note: candidate is:
test.cpp:29:37: note: template<int D, class T1, class T2> Vec<D, decltype ((T1() + T2()))> operator+(const Vec<D, T1>&, const Vec<D, T2>&)
 inline Vec<D, decltype(T1()+T2())>  operator + (const Vec<D,T1> &a, const Vec<D,T2> &b){       
                                     ^
test.cpp:29:37: note:   template argument deduction/substitution failed:
test.cpp:49:21: note:   deduced conflicting values for non-type parameter ‘D’ (‘1’ and ‘3’)
  std::cout<<(vec(1)+x)<<std::endl;
                     ^

Сорри за много букв. cast tailgunner

★★★★★

Последнее исправление: beastie (всего исправлений: 1)

Ответ на: комментарий от eao197

На самом деле в пользу SvVec есть еще один сильный аргумент - некоторые операции над векторами (скалярное умножение и модуль) зависят от размерности вектора, и для SvVec должны быть закрыты. Для Vec<1> их понятно закрыть нельзя.

Но тогда придется же весь кулек операций делать и для SvVec... если уж быть последовательным;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Ну я исходил из того, что если в сценариях использования явно прослеживается какой-то частный случай, то лучше этот случай выделить отдельной сущностью. Опыт показывает, что даже если это приводит к некоторому увеличению кода на начальном этапе, то при сопровождении все равно выигрываешь за счет простоты и понятности кода.

eao197 ★★★★★
()
Ответ на: комментарий от AIv

В том, что если в коде встречается сумма вектора и скаляра - это значит в коде (при наборе числ. схемы) возникла ошибка.

Т.е. значит операция вектор на скаляр уже просто занята?

Нет.

Хорошо.

Это в любом случае придется делать, особенное сли учесть что тип массива может отличаться от типа исходного массива;-)

Эта логика работает только чаров и шортов, зачем на неё полагаться? Она не работает для интов и выше. Её проще выпилить вообще. Да и как и зачем складывать инты с флоатами?

В смысле?

Если определить оператор как метод - нельзя узнать, что: vec() + a в данном случае сложение было инициировано из xvalue.

Хотя в случае с операторами-функциями можно.

AnonCxx
()
Ответ на: комментарий от AnonCxx

Т.е. значит операция вектор на скаляр уже просто занята?

Перемножать вектор и скаляр можно, а вот складывать нельзя. Сколько будет 3 яблока + 2 тапочка ?

Да и как и зачем складывать инты с флоатами?

Что бы получить флоат? 1+2.5==>3.5, в чем проблема? Это ладно, бывает что приходиться складывать флоты с комплексными числами...

Если определить оператор как метод - нельзя узнать, что: vec() + a в данном случае сложение было инициировано из xvalue.

А зачем мне это знать? Есть два операнда, мы их обрабатали и вернули результат. Ну и как бы первый операнд левый, вторый правый... в чем проблема?

AIv ★★★★★
() автор топика

имхо легче было в коде заменить vec(1) на vec<3>(1) чем столько флудить (как в коде, так и в комментариях)

anonymous
()
Ответ на: комментарий от AIv

Сколько будет 3 яблока + 2 тапочка ?

3 яблока и 2тапочка, либо пять предметов. {3, 0} + {0, 2} = {3, 2}.

Что бы получить флоат? 1+2.5==>3.5, в чем проблема?

флоат с одним знаком - это <21бита целой части, тогда как инт 32. Что на ~3 порядка меньше. Если числа влезают в этот диапазон - смысла в инте нет, если не влезают - смысла в результате нет.

Ну и плюс это дороже по времени исполнения.

Это ладно, бывает что приходиться складывать флоты с комплексными числами...

Я в этом ничего не понимаю.

А зачем мне это знать?

Для того, чтобы использовать под результат память одного из операндов, если это возможно.

Есть два операнда, мы их обрабатали и вернули результат. Ну и как бы первый операнд левый, вторый правый... в чем проблема?

Все эти операции упираются в память. Проблема в том, что по умолчанию это использует на 50% больше памяти - это первое.

Если функция не инлайн - там будет копирование результата, ибо вернуть из функции можно только копию. А копирование стоит столько же, сколько и сама операция.

В любом случае все временные объекты будут создаваться на стеке текущей функции и существовать до конца блока.

С каждой операцией стек будет расти и расти, но не это плохо.

Плохо то, что в следствии этого для каждой новой операции используется не горячая память, а холодная. А холодную память надо прочитать надо прочитать из более медленного источника.

AnonCxx
()
Ответ на: комментарий от AnonCxx

3 яблока и 2тапочка, либо пять предметов

А если каждый тапочек состоит из 3х апельсин?;-) В общем нельзя складывать вектора и скаляры. Если кажется что можно, это значит НЕЯВНО либо вектор приводится к скаляру, либо скаляр к вектору - и то и то чревато.

Если числа влезают в этот диапазон - смысла в инте нет, если не влезают - смысла в результате нет.

Мы это уже ЕМНИП обсуждали. В общем смысл есть, и такие операции на практике весьма востребованы.

Для того, чтобы использовать под результат память одного из операндов, если это возможно.

Для этого есть операция +=. Для простой операции + это некорректное поведение. Можно конечно мутить что то с &&, но я вообще полагаюсь на компилятор - он неплохо оптимизирует такие вещи.

AIv ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.