On Vox: Поигрался тут
Dec. 6th, 2009 04:28 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Кто-то (увы, не помню кто - напомните?) не так давно предлагал вопрос для интервью соискателям: где в C++ находится параметрический полиморфизм? Правильный ответ был "в районе шаблонов". Соответственно, я бы предложил следующий вопрос: а почему шаблоны таки не являются параметрическим полиморфизмом? Правильный ответ: потому что это всего лишь макросы на стероидах. Реализация метапрограммирования. А метапрограммирование ничего не может сделать, если под ним находится слишком слабенькая система.
Вот в чём сие выражается. Я запостил на ЛОР задачку (сопроводив её кодом на Хаскеле): подсчитать скалярное произведение двух векторов, статически гарантировав, что они имеют одинаковую длину. Мне не интересно сейчас снова демонстрировать, как это делается на Хаскеле (очень просто), но даже на C# вот такой код вполне работает:
Однако, переписав этот код почти один в один на C++ (с шаблонами вместо дженериков), получаем... нерабочий код:
using System;
interface ScalarProduct<A> {
int scalarProduct(A second);
}
class Nil : ScalarProduct<Nil> {
public Nil(){}
public int scalarProduct(Nil second) {
return 0;
}
}
class Cons<A> : ScalarProduct<Cons<A>> where A : ScalarProduct<A> {
public int value;
public A tail;
public Cons(int _value, A _tail) {
value = _value;
tail = _tail;
}
public int scalarProduct(Cons<A> second){
return value * second.value + tail.scalarProduct(second.tail);
}
}
class _Test{
public static int main(int n){
return _main(n, 0, new Nil(), new Nil());
}
public static int _main<A>(int n, int i, A first, A second) where A : ScalarProduct<A> {
if (n == 0) {
return first.scalarProduct(second);
} else {
return _main(n-1, i+1, new Cons<A>(2*i+1,first), new Cons<A>(i*i, second)); // Works
//return _main(n-1, i+1, first, new Cons<A>(i*i, second)); // Doesn't work
}
}
}
public class Test{
public static void Main(){
Console.Write("Enter a number: ");
int val = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(_Test.main(val));
}
}
Бесконечное развёртывание шаблонов.
#include <iostream>
template <class A> class ScalarProduct {
public:
virtual int scalarProduct(const A &second) const = 0;
};
class Nil : public ScalarProduct<Nil> {
public:
Nil(){}
virtual int scalarProduct(const Nil &second) const {
return 0;
}
};
template <class A> class Cons : public ScalarProduct<Cons<A> > {
public:
int value;
const A &tail;
Cons(int _value, const A &_tail) : value(_value), tail(_tail) {}
virtual int scalarProduct(const Cons<A> &second) const {
return value * second.value + tail.scalarProduct(second.tail);
}
};
class _Test {
public:
static int main(int n){
return _main<Nil>(n, 0, Nil(), Nil());
}
template <class A> static int _main(int n, int i, const A &first, const A &second){
if (n == 0) {
return first.scalarProduct(second);
} else {
return _main(n-1, i+1, Cons<A>(2*i+1,first), Cons<A>(i*i, second)); // Doesn't work
//return _main(n-1, i+1, Cons<Nil>(2*i+1, Nil()), Cons<Nil>(i*i, Nil())); // Works, but isn't what we want
}
}
};
int main(int argc, char* argv[]){
std::cout << "Enter a number: ";
int val;
std::cin >> val;
std::cout << _Test::main(val) << std::endl;
return 0;
}
Джавский вариант тоже, разумеется, работает.
Originally posted on migmit.vox.com
no subject
Date: 2010-02-14 03:48 am (UTC)>Знаете, я думал, мы про алгоритмы говорим, а не про подобную фигню.
Алгоритмы? А в соседнем комменте
>> Угу, так случайно получим O(N^2) вместо O(N).
>Глубоко по барабану. Речь о полиморфизме.
>Ну, возьмите шарп, если хотите использовать базовые типы в дженериках.
Чем тут шарп лучше? Можно складывать строки плюсиком, но интерфейса нет, а от string не унаследуешься -- как и в жабе, пишите обертку на три листа, Шура, пишите.
no subject
Date: 2010-02-14 09:13 am (UTC)Именно. Более конкретно - о полиморфизме. А вы считаете, он нужен для чего-то, кроме реализации алгоритмов?
> Чем тут шарп лучше?
Вы тупой? Сами же цитируете: в нём можно использовать базовые типы в дженериках.
> как и в жабе, пишите обертку на три листа
Хотя я согласен, что и шарп, и жаба весьма многословны, но ваши "три листа" - явный перебор.
no subject
Date: 2010-02-16 05:47 am (UTC)>Именно. Более конкретно - о полиморфизме. А вы считаете, он нужен для чего-то, кроме реализации алгоритмов?
Как минимум еще одно применение: для троллинга на ЛОРе.
>> как и в жабе, пишите обертку на три листа
>Хотя я согласен, что и шарп, и жаба весьма многословны, но ваши "три листа" - явный перебор.
Ну так загляните в документацию, сколько у string конструкторов и методов.
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html
no subject
Date: 2010-02-16 07:31 am (UTC)И вам в вашей задаче нужно оборачивать просто-таки все.
no subject
Date: 2010-02-18 10:15 am (UTC)А что, я не имею права написать
char q = summ(strings).replace(s1,s2).charAt(5); ?
no subject
Date: 2010-02-14 09:51 am (UTC)no subject
Date: 2010-02-16 05:56 am (UTC)Да, правда к Java этот язык имеет такое же отношение как тезис "а если бы у бабушки были яйца".
no subject
Date: 2010-02-16 07:30 am (UTC)