[C++]Как написать шаблон?

apl13

Забавная такая проблема. Решил, для примера, сделать комплексные числа. Пишу
template <typename R> complex {
template <typename F> operator+(complex<F> &b);
template <typename F> operator+(F b);
}

, имея в виду, что одно дело - прибавить к комплексному числу комплексное число, другое дело - прибавить к нему же число вещественное.
Компилятор, встретив
complex<double> a, b;
a = a + b;

не знает, какой из вариантов сложения взять.
А я не знаю, что ему посоветовать. :crazy:
Тут можно что-нибудь сделать?

procenkotanya

Нафига члены-то новым типом F параметризовать?

ppplva

Чтобы складывать complex<double> и complex<int>? Хотя, наверное, правильнее будет определить соответствующий конструктор.
Хз почему, но у меня твой код работает (если дописать типы возвращаемых значений и прочую неинтересную ерунду):
template <typename R>
class complex {
public:
R r, i;

complex(R r_, R i_) : r(r_ i(i_) {}
complex : r(0 i(0) {}

template <typename F> complex<R> operator+(complex<F> &b) {
return complex<R>(r + b.r, i + b.i);
}

template <typename F> complex<R> operator+(F b) {
return complex<R>(r + b, i);
}
};

int main(void) {
complex<double> a, b;
complex<int> c, d;
double e;
int f;
a = a + b;
c = c + d;
c = c + a;
a = a + c;
a = b + e;
c = d + f;
}

apl13

А ты чем собираешь?

sasha79

У меня gcc version 4.0.1 (Apple Inc. build 5465 собирается тоже.

agaaaa

template <class T> class complex{
private:
T re_, im_;
public:
complex{}
complex(T re, T im): re_(re im_(im){}
template <class F> complex<T> operator+(const complex<F> &other)
{
return complex(re_ + other.re_, im_ + other.im_);
}
template <class F> complex<T> operator+(const F &other)
{
return complex(re_ + other, im_);
}
};

void f
{
complex<double> a, b;
a = a + b;
}

VS 2008, компилируется.

ppplva

gcc 4.3.2

stat7984215

А кто-нибудь может объяснить почему в этом коде

template <class T> class complex{
private:
T re_, im_;
public:
complex{}
complex(T re, T im): re_(re im_(im){}
template <class F> complex<T> operator+(const complex<F> &other)
{
return complex(re_ + other.re_, im_ + other.im_);
}
template <class F> complex<T> operator+(F &other)
{
return complex(re_ + other, im_);
}
};

int main
{
complex<double> a, b;
a = a + b;
}

компилятор (проверял на gcc и comeau online) выбирает второй operator+, а если заменить тип параметра на константную ссылку, то выбирает первый?

agaaaa

омпилятор (проверял на gcc и comeau online) выбирает второй operator+
быть такого не может

stat7984215

быть такого не может
test.cpp:

#include <iostream>

template <class T> class complex{
private:
T re_, im_;
public:
complex{}
complex(T re, T im): re_(re im_(im){}
template <class F> complex<T> operator+(const complex<F> &other)
{
return complex(re_ + other.re_, im_ + other.im_);
}
template <class F> complex<T> operator+(F &other)
{
std::cout << "Ooops!" << std::endl;
// return complex(re_ + other, im_);
}
};

int main
{
complex<double> a, b;
a = a + b;
}


mutant ~ $ g++ test.cpp
mutant ~ $ ./a.out
Ooops!

agaaaa

Разъясните двоечнику как это работает, пожалуйста.
Сам разобрался.
Автор, верни возвращение комплекса, тогда код не будет компилироваться, т.к. не будет констуктора complex(complex, double). Без него второй вариант подходит лучше, т.к. в нём не нужно кастить к константному объекту.

stat7984215

На самом деле, если там раскомментировать return, то код не будет компилироваться уже из-за того, что не найдется operator+(double, complex до конструктора дело даже не дойдет.
А вот про то, что при выборе перегрузки константность аргумента важнее его типа я не знал :o

agaaaa

А вот про то, что при выборе перегрузки константность аргумента важнее его типа я не знал
А тут уже ты не понял. Во второй перегрухке он считает, что F == complex<double> и потому что complex<double> & - ближе к complex<double>, чем const complex<double> &

stat7984215

Да, верно. Что-то я ступил :o

rosali

вынеси оператор из класса и специализируй его:

[xoft ~]$ cat xxx.cpp
#include <iostream>
using namespace std;

template <class R> struct complex {
complex(R x, R y): x(x y(y) {}
R x;
R y;
};

template <class R, class F>
complex<R> operator+(complex<R> z1, F x2) {
cout << "operator+(complex<R> z1, F x2)" << endl;
return complex<R>(z1.x+x2, z1.y);
}

template<class R, class F>
complex<R> operator+(complex<R> z1, complex<F> z2) {
cout << "operator+(complex<R> z1, complex<F> z2)" << endl;
return complex<R>(z1.x+z2.x, z1.y + z2.y);
}

int main {
complex<double> c(0.5, 0.6);
c + 1;
c + c;
return 0;
}

[xoft ~]$ ./xxx
operator+(complex<R> z1, F x2)
operator+(complex<R> z1, complex<F> z2)

PS. передача параметров по ссылке тоже компилируется.
PSS. gcc version 4.2.3

erotic

template <typename F> operator+(complex<F> &b);
template <typename F> operator+(F b);
Вообще старайся писать более общие варианты перед узкоспециализированными.

rosali

=) это лишь особенность мышления css+xslt программистов, не более ;)

sergeikozyr

Это хаскель - там более общие идут после тех, что уже. Имхо, так логичнее.

rosali

ну я про это и говорил, в хаскеле и похожих языках частное пишут вверху, потому что как бы подразумевается if/elseif/elseif/..., а в css и в xslt пишут общее вверху, подразумевая override-ы. и так и так логично выглядит, не надо из этого каких-то фундаметнальных выводов делать :) но мне кстати xslt-шный стиль симпатишнее кажется, он применим и при отсутствии локальности, написал override в основной программе и не надо париться, есть какое-то более общее определение в какой-нибудь используемой библиотеке или нет.

erotic

=) это лишь особенность мышления css+xslt программистов, не более
Вовсе нет, просто специализации шаблонов обязаны идти после описаний более общих определений.
Оставить комментарий
Имя или ник:
Комментарий: