Managed обертка для std::Vector
Для этого используя сборку на С++.NET.
В принципе это не особо сложно за одним исключением, я решил сохранить за Вектором возможность хранить произвольные типы (int, double, bool).
Помучившись в течении некоторового времени привожу результат:
Проект С++.Net ClassLibrary VS2008:
#pragma once
#include <vector>
#include "stdafx.h"
#include <objbase.h>
using namespace System;
using namespace std;
#define PVOID void*
#define INVI inline virtual
#define IN inline
namespace VC {
/* Создание интерфейса с функциями, которые будем использовать*/
public interface IVECTOR{
INVI void push_back ( PVOID var) =0;
INVI void pop_back () =0;
INVI void erase (int &index) =0;
INVI void inrease (int &index, PVOID var) =0;
INVI PVOID back () =0;
INVI PVOID front () =0;
INVI int size () =0;
INVI PVOID operator[] (int &t) =0;
};
/* Наследуем template Vector от интерфейса, описываем функции интерфейса*/
template<typename type>
public class TempVECTOR: public IVECTOR
{
public:
vector<type> Vec; //Создаем вектор плавающего типа, для последующей работы с ним
INVI void push_back(PVOID var) { Vec.push_back(*(type*)var); }
INVI void pop_back() { Vec.pop_back(); }
INVI void erase(int &index) { Vec.erase(Vec.begin()+index); }
INVI void inrease(int &index, PVOID var) { Vec.insert(Vec.begin()+index,*(type*)var); }
INVI PVOID back() { return (PVOID)&Vec.back(); }
INVI PVOID front() { return (PVOID)&Vec.front(); }
INVI int size() { return Vec.size(); }
INVI PVOID operator[](int &t) { return (PVOID)&Vec[t]; }
};
}
using namespace VC;
//Создаем Вектор и возвращаем его как интерфейс
IVECTOR* Release(TypeCode ctype){
switch(ctype)
{
case TypeCode::Int32: {return new TempVECTOR<Int32>();break;}
case TypeCode::Double: {return new TempVECTOR<Double>();break;}
case TypeCode::Char: {return new TempVECTOR<Char>();break;}
case TypeCode::Boolean: {return new TempVECTOR<Boolean>();break;}
case TypeCode::Int64: {return new TempVECTOR<Int64>();break;}
case TypeCode::UInt32: {return new TempVECTOR<UInt32>();break;}
case TypeCode::SByte: {return new TempVECTOR<SByte>();break;}
case TypeCode::Byte: {return new TempVECTOR<Byte>();break;}
case TypeCode::Int16: {return new TempVECTOR<Int16>();break;}
case TypeCode::UInt16: {return new TempVECTOR<UInt16>();break;}
case TypeCode::UInt64: {return new TempVECTOR<UInt64>();break;}
case TypeCode::Single: {return new TempVECTOR<Single>();break;}
}
return NULL;
}
////////
namespace VC {
//Описываем сам переносимый класс
public ref class Vector
{
protected:
IVECTOR *IV; //Указатель на интерефейс вектора типа(TypeCode ctype)
public:
//Конструктор вектора базового типа
Vector(TypeCode ctype) {IV=Release(ctype);}
inline void push_back(PVOID var) {IV->push_back(var);}
inline void pop_back() {IV->pop_back();}
inline void erase(int index) {IV->erase(index);}
inline void increase(int index,PVOID var)
{IV->inrease(index,var);}
inline PVOID back() {return IV->back();}
inline PVOID front() {return IV->front();}
inline int size() {return IV->size();}
inline PVOID top(int t) {return (*IV)[t];}
};
}
Основные недостатки:
1) Среди хранимых типов данных доступны только типы System::TypeCode. И то лишь те, которые имеют фиксированный размер.
2) Возвращаемые значения имеют тип void* (PVOID - в коде), что приводит к необходимости, допустим возвращая тип (int) в С# писать следующие конструкции: *(int*)vec.back().
И вот следующие вопросы:
1) Как в С# получать указатели на небазовые простые классы, а допустим получить указатель или адресс переменной типа System::String, не говоря уже допустим про структуры.
2) Есть ли возможность наладить восприятие generic<typename gtype> ~ template<typename ttype>, т.е. перевести generic тип в native code.
Буду рад любым вашим идеям.:)
Что такое "небазовый простой класс"? Переформулируй, плиз
Читай про Object class и его метод GetType. В обертке делай преобразование. Вообще эта задача в общем виде нерешаемая, т.к. generic<typename gtype> - это конструкция времени исполнения, а template<typename ttype> - конструкция времени компиляции. Сформулировал криво, но, надеюсь, смысл понятен.
Вернее будет сказать небазовый простой тип. Unsafe code C# поддерживает указатели на базовые value типы (там int, byte, float, double, .....).
Поэтому при аолучении (void*) указателя его сожно преобразовать допустим в inf следующей процедурой: *(int*)(указатель типа void*).
А если допустим у меня кть потребность закинуть туда:
struct XY{ int x,y; };
Тогда ее уже не вытащишь *(XY*)(указатель типа void*) потому как компилятор скажет что указатели на XY невозможен.
Я вроде как нашел, что для этой цели можно использовать System::IntPtr, вот только как это корректно сделать - я не нашел.
Мож кто знает?
public ref class Vector
where T : ISerializable
{
};
Хотя, если чесно, фигнёй страдаете. В FCL есть более гибкие и удобные коллекции (например, вариации на тему List).
И ещё не ясно, зачем передавать ссылки на int в erase() и increase().