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

★★★★★

http://en.cppreference.com/w/cpp/language/template_argument_deduction#Implicit_conversions

Type deduction does not consider implicit conversions: that's the job for overload resolution, which happens later.

utf8nowhere ★★ ()

У вас нету оператора сложения для Vec<N,int> + Vec<M,int> (есть только для Vec<N,int> + Vec<N,int>. можно подправить оператор вот так:

template <int D1, int D2, typename T1, typename T2>
inline Vec<D1, decltype(T1()+T2())>  operator + (const Vec<D1,T1> &a, const Vec<D2,T2> &b){
        Vec<D1, decltype(T1()+T2())> r;
        for(int i=0; i<D1; i++) r[i] = a[i]+b[i];
        return r;
}
Но сами понимаете теперь его реализация малось не корректная (a и b имеют раличную размерность и там идет обращение за пределы массивов)

zaz ★★★★ ()

test.cpp:49:20: error: no match for ‘operator+’ (operand types are ‘Vec<1, int>’ and ‘Vec<3, int>’)

У тебя его и в самом деле нет. Твой operator+ определен так, что у аргументов должна быть одна размерность.

tailgunner ★★★★★ ()

Vec<1,T1>...Vec<D,T1> - D разных, никак не связанных друг с другом типов. Для достижения успеха нужно определить разные operator+() относительно D. Обрати внимание, что он объявлен как:

template <int D, typename T1, typename T2>
inline Vec<D, decltype(T1()+T2())>  operator + (const Vec<D,T1> &a, const Vec<D,T2> &b){
т.е. нормально относится к T1 и T2, но не умеет в разные D.

jcd ★★★★★ ()

Вот добавил более «правильный фикс»

constexpr int DMAX(int n1, int n2) { return (n1 > n2) ?n1 :n2; };

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

zaz ★★★★ ()
Последнее исправление: zaz (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Спасибо, я в курсе;-)

Я с-но и хочу сделать так, что бы за счет конвертации Vec<1,T>==>Vec<D,T> это работало. Если это в принципе возможно.

Иначе каждый оператор придется перегружать трижды, кроме того непонятно что будет с Vec<1,T>+Vec<1,T>

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

Если ты хотел спросить «как мне определить опрератор сложения для векторов разной длины», то ответ выше.

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

Мне нужно в итоге три оператора сложения:

Vec<D,T1>+Vec<D,T2>
Vec<1,T>+Vec<D,T>
Vec<D,T>+Vec<1,T>
Могу ли я это сделать определив только
Vec<D,T1>+Vec<D,T2>
и задав каким то образом неявное приведение Vec<1,T> к Vec<D,T> (или еще как то увернуться от задания двух других операторов)?

Или utf8nowhere правильно цитирует, что это вообще сделать никак нельзя?

Перегрузка операций (комментарий)

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

Тем, что мне не нужен например оператор Vec<3>+Vec<2> - он должен быть закрыт. Хотя можно наверное влепить туда static_assert или еще какую хрень... гипотетически в этом случае можно ожидать более вменяемых сообщений об ошибке;-)

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

Тогда все валится для Vec<1> - у компайлера три эквивалентных варианта.

Остается либо static_assert (что на самом деле неплохо, но усложняет код каждого оператора), либо возиться с неявным приведением... я че то думал что неявное приведение заработает, а вот фига.

Какие еще варианты есть?

AIv ★★★★★ ()
Последнее исправление: AIv (всего исправлений: 1)
Ответ на: комментарий от AIv

Так, вроде, работает (это после operator +):

template <int D1, int D2, typename T1, typename T2>
inline typename
std::enable_if<D1 == 1 || D2 == 1,
               Vec<D1 + D2 - 1, decltype(T1()+T2())>>::type
operator + (const Vec<D1,T1> &a, const Vec<D2,T2> &b){
    return operator +<D1 + D2 - 1, decltype(T1()+T2())>(a, b);
}

// Это не обязательно, просто для сообщения, что функция удалена явно.
template <int D1, int D2, typename T1, typename T2>
typename std::enable_if<D1 != D2 && D1 != 1 && D2 != 1>::type
operator + (const Vec<D1,T1> &a, const Vec<D2,T2> &b) = delete;

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

Так... спасибо, с enable_if не сталкивался, буду изучать;-)

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

Что-то ты какую-то херню написал. Почему это длины векторов складываются, когда должны складываться вектора одной длины покомпонентно; или, если кто-то из них длины 1, то он должен удлиняться до другого (неявно, с помощью соотв. конструктора, для чего я упомянул is_convertible) и после этого складываться, опять же покомпонентно.

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

Если один из векторов длины 1 (а там проверка), то (D1 + D2 - 1) даст длину второго. Преобразование сделает сам же компилятор, так как тип шаблона указан явно. Правда decltype там не нужен:

-     return operator +<D1 + D2 - 1, decltype(T1()+T2())>(a, b);
+     return operator +<D1 + D2 - 1, T1, T2>(a, b);

xaizek ★★★★★ ()
Последнее исправление: xaizek (всего исправлений: 1)
Ответ на: комментарий от xaizek

А, теперь понял. Просто я думал сделать одну шаблонную функцию, и для одинаковых длин, и для приведения типов.

utf8nowhere ★★ ()

Вот, что я родил

constexpr int DMAX(int n1, int n2)
{
	return (n1 > n2) ? n1 : n2;
};

template <int D1, int D2, typename T1, typename T2,
          int D = DMAX(D1, D2),
          typename = std::enable_if_t<D1 == D2 || D1 == 1 || D2 == 1>>
decltype(auto) operator+ (const Vec<D1,T1> &_a, const Vec<D2,T2> &_b)
{
	const Vec<D, T1>& a = _a;
	const Vec<D, T2>& b = _b;
	Vec<D, decltype(T1()+T2())> r;

	for(int i=0; i<D; i++)
		r[i] = a[i]+b[i];
	return r;
}

tailgunner, покритикуй.

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

Это слишком сложно для меня. Вроде всё круто, но, возможно, я просто не вижу граблей.

tailgunner ★★★★★ ()

Всё же лучше написать 3 реализации оператора сложения и обойтись без приведения типов, а не как у xaizek или у меня. Пусть операторы, принимающие одномерный вектор, явно прибавляют его значение к элементам другого.

Это будет вполне в байтослесарском C++-стиле: быстродействие за счёт раздувания кода. Такой стиль особенно оправдан для подобного числодробильно-ориентированного типа.

Как справиться с неоднозначной инстанциацией шаблонов при сложении двух одномерных векторов ты уже знаешь.

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

Со дной стороны раздувание кода не большая проблема, я все равно это в макрос завертываю (иначе очень много букв на все операции).

С другой стороны, разве компайлер не соптимизирует вариант с приведением типов?

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

А почему надо именно такой кастыль с vec<1> - почему бы не сделать как-то так:

template<typename T, size_t n> class __vec {
public:
  __vec() {}

  __vec(std::initializer_list<T> arglist) {
    std::copy(std::begin(arglist), std::end(arglist), std::begin(p));
  }

  auto begin() const { return std::begin(p); }
  auto end() const  { return std::end(p); }
  auto begin() { return std::begin(p); }
  auto end()  { return std::end(p); }

  template<typename To> auto operator+(const __vec<To, n> & o) const {
    __vec<decltype(To{} + T{}), n> ret;
    std::generate(std::begin(ret), std::end(ret), [a = std::begin(*this), b = std::begin(o)]() mutable {
      return *a++ + *b++;
    });
    return ret;
  }

  template<typename Ts> using enable_if_arithmetic_t = std::enable_if_t<std::is_arithmetic<Ts>::value>;

  template<typename Ts, typename = enable_if_arithmetic_t<Ts>> auto operator+(Ts s) const {
    __vec<decltype(Ts{} + T{}), n> ret;
    std::generate(std::begin(ret), std::end(ret), [a = std::begin(*this), s]() mutable {
      return *a++ + s;
    });
    return ret;
  }

  friend std::ostream & operator<<(std::ostream & out, const __vec & vec) {
    out << "vec<" << n << ",szT=" << sizeof(T) << ">:";
    std::copy(std::begin(vec), std::end(vec), std::ostream_iterator<T> {out, " "});
    return out;
  }

  template<typename Ts, typename = enable_if_arithmetic_t<Ts>> friend auto operator+(Ts s, const __vec<T,n> & v) {
    return v + s;
  }

private:
  T p[n];
};



template<typename ... args> static inline auto vec(args ... arg) {
  using T = std::common_type_t<args...>;
  return __vec<T, sizeof...(args)>{static_cast<T>(arg)...};
}

int main() {
  std::cout << 10 + vec(10, 20, 30) + vec(10, 20, 20)  + 10.3 << std::endl;
}

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

Потому что 10+vec(...) некорректная операция и должна быть запрещена.

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

А что тогда: Vec<1,T1>+Vec<D,T2>

Судя по:

 Vec(const Vec<1, T> &v){ for(int i=0; i<D; i++) p[i] = v[0]; }

При касте к Vec<D, T1> - это будет значение Vec<1,T1> во всех элементах. Т.е. Vec<1,T1>(10)+Vec<3,T2>(10, 20, 30) - должно быть {20, 30, 40}.

Либо я что-то не понимаю?

В этой(Перегрузка операций (комментарий)) реализации такое же поведение.

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

Именно так.

Запись Vec<D, T>(x) явно указывает, что надо сделать вектор размерности D содержащий х во всех компонентах, но она слишком громоздка, кроме того при изменении размерности надо не забыть в ней поменять D. Хочется просто писать vec(x) когда надо сделать вектор произвольного размера содержащий x во всех компонетах. Это вполне корректно - мы явно указываем что работаем именно с вектором. На самом деле такая операция на удивление асто бывает нужна;-(

А вот x+Vec<> надо закрывать, потому что в сложных выражениях это будет приводить к аццким ошибкам - все компилируется но работает неправильно, и хрен найдешь почему. Нельзя складывать ветокр и скаляр.

AIv ★★★★★ ()

А что будет если сделать Vec<3> y{1,2}; ?

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

Хочется просто писать vec(x) когда надо сделать вектор произвольного размера содержащий x во всех компонетах.

Но это невозможно - откуда взять D?

При этом vec(x) - это оверхед. Зачем писать при каждом сложении D чисел, чтобы в конечном итоге прочитать одно значение.

А вот x+Vec<> надо закрывать, потому что в сложных выражениях это будет приводить к аццким ошибкам - все компилируется но работает неправильно, и хрен найдешь почему.

А как оно может работать неправильно? Оно работает только при сложении с векторами, если там не вектор - работать не будет.

Размерность у неё всегда такая(её и нет), какая и у вектора, в которого добавляем.

Сложение вектором работает только для тех, у которых D совпадает. Можно добавить ещё проверку, чтобы работало только для арифметических типов, как в 10 + vec().

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

Должно упасть при компиляции. Если не падает, надо поправить что бы падало;-)

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

Но это невозможно - откуда взять D?

Vec<1> трактуется как вектор любой размерности.

Зачем писать при каждом сложении D чисел, чтобы в конечном итоге прочитать одно значение.

Согласен. Поэтому надо делать три операции: Vec<D>+Vec<D>, Vec<D>+Vec<1> и Vec<1>+Vec<D>

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

Либо проверяй в рантайме, либо делай три перегрузки, в чем проблема?

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

Хочется просто писать vec(x) когда надо сделать вектор произвольного размера содержащий x во всех компонетах.

Почему бы тогда не сделать отдельный тип SvVec<T> (single-value vector), который бы содержал только одно значение? А затем определить операторы сложения: Vec<D,T>+Vec<D,T>, SvVec<T>+Vec<D,T>, Vec<D,T>+SvVec<T>...

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

Я думал над этим. С одной стороны так конечно строже получается. С другой - не так много хороших коротких индентификаторов. Мне нужна функция порождающая вектора размерности по чиcлу аргументов, это vec(...)

vec(1,2,3) ==> Vec<3>(1,2,3) 
и ф-я для создания SvVec. Пока что я решил что это будет одна функция, тем более что Vec<1> как раз одно значение и содержит.

В общем субъективно мне пока что больше нрав. вариант с перегрузкой для Vec<1>, хотя я до конца не уверен. Не исключаю что могут быть грабли какие то в таком решении...

AIv ★★★★★ ()
Последнее исправление: AIv (всего исправлений: 1)
Ответ на: комментарий от AIv

Мне нужна функция порождающая вектора размерности по чиcлу аргументов, это vec(...)
и ф-я для создания SvVec.

Я фигею с этих умных. Вам не лень сделать специализацию Vec<D,T> для D=1, которая ведет себя совсем не так, как для остальных значений D, вам не лень делать специализации операторов сложения (а потом, возможно и еще каких-то операторов), вам не лень весь этот набор частностей потом отлаживать и сопровождать... И все только для того, чтобы иметь возможность везде писать vec(x), vec(x,y), vec(x,y,z) и т.д.?

Блин, где бы взять столько терпения, усидчивости и скрупулезности. Можно предположу: вы окончили школу с медалью, а ВУЗ с красным дипломом?

По вашей проблеме: ну так сделайте так, чтобы vec(x) возвращал SvVec<T>(x), а vec(x,y,z) возвращал Vec<3,T>(x,y,z):

template< typename T > auto vec(T v) {
  return SvVec<T>(v);
}
template< typename T, typename... R > auto vec(T v, R ...rest) {
  return Vec<1+sizeof...(R), T>(v, std::forward<R>(rest)...);
} 

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

О какой именно специализации Вы говорите? Если о специализации операций (которые объявляются как внешние) - так ее все равно так или наче делать, хоть для Vec<1,T> хоть для SvVec<T>.

Если про специализацию для Vec<1,T> - так ее делать не надо.

Разница между этими двумя решения три что ли строчки...

сделайте так, чтобы vec(x) возвращал SvVec<T>(x), а vec(x,y,z) возвращал Vec<3,T>(x,y,z)

А что делать, когда нужен Vec<1,T>?

Есть принцип старины Оккама, так вот SvVec<T> мне пока что кажется лишней сущностью.

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

О какой именно специализации Вы говорите?

Я говорю о том, что если у вас есть шаблон Vec<D,T> и какая-то операция f для этого шаблона и эта операция f должна вести себя по-разному для разных значений D, то вы будете делать не перегрузку f, а специализацию.

А что делать, когда нужен Vec<1,T>?

Вы уж определитесь, будет ли у вас Vec<1,T> вести себя точно так же, как и Vec<D,T> (где D — это любое значение). А то вы для D=3, например, хотите одно поведение, а для D=1 — уже другое. И Vec<1,T> у вас может как содержать всего один элемент, так и N элементов с одинаковым значением.

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

Однако лично мне (лично мне) было бы стремно использовать библиотеку векторов, в которой Vec<1,int>(1) + Vec<3,int>(1,2,3) давал точно такой же результат, как и Vec<3,int>(1,1,1) + Vec<3,int>(1,2,3). Поскольку из этого следует, что Vec<1,int>(1) == Vec<3,int>(1,1,1), что несколько противоречит здравому смыслу (моему, по крайней мере).

Есть принцип старины Оккама, так вот SvVec<T> мне пока что кажется лишней сущностью.

Дело ваше. Вам же жить с тем, что вы понапридумаете.

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

Я говорю о том, что если у вас есть шаблон Vec<D,T> и какая-то операция f для этого шаблона и эта операция f должна вести себя по-разному для разных значений D, то вы будете делать не перегрузку f, а специализацию.

Спасибо Кэп. А если у меня есть SvVec, то для него прижется делать перегрузку, которая от специализации Vec<1,T> отличается чуть более чем никак.

Поскольку из этого следует, что Vec<1,int>(1) == Vec<3,int>(1,1,1),

Именно так;-)

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

Спасибо Кэп. А если у меня есть SvVec, то для него прижется делать перегрузку, которая от специализации Vec<1,T> отличается чуть более чем никак.

Всегда пожалуйста. И раз вам так нравятся мои советы, то позволю себе напомнить, что перегружать функции/операторы разными типами аргументов в C++ несколько проще, чем делать частичную специализацию этих самых функций/операторов. А ведь вам придется делать именно что частичную специализацию. Так что удачи.

Именно так

У меня, видимо, какая-то своя линейная алгебра, провинциальная, из церковно-приходской школы.

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

сравните

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

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

У меня, видимо, какая-то своя линейная алгебра, провинциальная, из церковно-приходской школы.

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

У меня же например операция & перегужена для покомпонентного перемножения векторов - в линейке нету, а в жизни сплошь и рядом встречается...

AIv ★★★★★ ()
Последнее исправление: AIv (всего исправлений: 1)
Ответ на: комментарий от AIv

сравните

Видимо, я испорчен кроссплатформенностью и необходимостью иметь дело с компиляторами, в которых поддержка SFINAE не так хороша, как в gcc и clang.

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

Я когда то что то под MINGW собирал... а что, там enable_if не работает?

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

У меня регулярно бывали проблемы с enable_if под VC++.

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

Ну VC++ не является целевой платформой (чур меня;-)), а вот MINGW надо потестить, спасибо.

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

Так MinGW — это же порт обычного GCC. У меня все, что успешно собирается GCC под Linux-ом не менее успешно собирается той же версией GCC под Windows (пользуюсь MinGW-w64).

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

Ну тогда вообще все хорошо. Правда еще иногда коллеги юзают интеловский компайлер.

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

Vec<1> трактуется как вектор любой размерности.

А в чём проблема трактовать за любую размерность «скаляр»?

Согласен.

Но тогда это уже вообще не вектор, а такой же скалаяр замаскированный под вектор.

Поэтому надо делать три операции: Vec<D>+Vec<D>, Vec<D>+Vec<1> и Vec<1>+Vec<D>

От создания одного массива это избавит, но останется создание второго массива, в который помещается результат. Надо ещё создавать дополнительные операции, которые бы использовали один из аргументов, если он xvalue.

Но насколько я понимаю в крестах нельзя определить тип значения.

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

Если про специализацию для Vec<1,T> - так ее делать не надо.

Почему? По мне так проще сделать специализацию и использовать методы-операторы, чем писать тонну лапши в функция-операторах.

Там хватит:

template<typename T> class __vec<T, 1> {
public:
  __vec(T s) : p{s} {}
  template<typename Tv, size_t nv> auto operator+(const __vec<Tv, nv> & v) const { static_assert(nv > 1, ""); return v + *this;}
  T p[1];
};
AnonCxx ()
Ответ на: комментарий от AnonCxx

А в чём проблема трактовать за любую размерность «скаляр»?

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

Но тогда это уже вообще не вектор, а такой же скалаяр замаскированный под вектор.

Нет.

От создания одного массива это избавит, но останется создание второго массива, в который помещается результат.

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

Но насколько я понимаю в крестах нельзя определить тип значения.

В смысле?

По мне так проще сделать специализацию и использовать методы-операторы, чем писать тонну лапши в функция-операторах.

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

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

я не спец в С++ и шаблонах, но решение, правильное с т.з. здравого смысла и культуры программирования (на мой взгляд), - это когда есть Vec(x), который возвращает тип Вектор, проинициализированный x-ом где надо. Иными словами, это должен быть конструктор соответствующего класса Вектор. Размерность можно задавать по-разному, хотя бы и явным образом: Vec(D,x)

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