2015-12-02 4 views
1

Я кодирую dll C++ для сортировки SAFEARRAY, переданного из VBA.Сортировка массива индексов в первичный массив

Я не использую никаких библиотек OLE, а получаю доступ к дескриптору массива и данным напрямую.

У меня нет проблем с сортировкой массива любых родных типов VBA. Например, следующий фрагмент сортирует массив BSTRs:

long * p = (long*)pData; 

std::sort(p, p + elems, comparestring); 

... который использует эту функцию сравнения:

bool comparestring(const long& lhs, const long& rhs) { 

    wchar_t * lhs_ = (wchar_t*)lhs; 
    wchar_t * rhs_ = (wchar_t*)rhs; 

    return _wcsicmp(lhs_, rhs_) < 0; 
} 

Я понимаю, что я обманывал здесь с wchar_t очень отличается от BSTR, но обычно не имеет нулевого символа в пределах полезной нагрузки строки Excel, и поэтому я в порядке с этим. Это хорошо работает.

ПРОБЛЕМА

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

Мои исследования показывают, что функтор lamda может быть наиболее перспективным путем, поскольку я бы предпочел не выделять память для дополнительных массивов или векторов данных или пар.

В частности, this answer seems very promising.

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

Я попытался следующие:

long * p = (long*)pData; 

long ndx[5]; 

for (int i = 0; i < 5; i++) ndx[i] = i + 1; 

std::sort(ndx[0], ndx[4], [&p](long i1, long i2) { comparestring((*p) + i1, (*p) + i2); }) 

Я использую VC++ 2015 и выше приводит к следующей ошибке:

Error C2893 Failed to specialize function template 'iterator_traits<_Iter>::iterator_category std::_Iter_cat(const _Iter &)'

Мои дни C программирования древней истории (предшествовавший существование C++), и поэтому я немного борюсь. Цените любую помощь.

UPDATE

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

long * p = (long*)pData; 

long ndx[5]; 

for (int i = 0; i < 5; i++) ndx[i] = i + 1; 

std::sort(ndx, ndx + 5, [&p](long i1, long i2) { return comparestring(*p + i1, *p + i2); }) 
+0

Лямбда должна возвращать логическое значение (например, 'вернуть CompareString .....' –

+0

также вы, вероятно, имел в виду 'NDX, NDX + 5' вместо' ndx [0], ndx [4] '.Это должно заставить его скомпилировать, но мне кажется, что ваш hackery-указатель-манипулятор по-прежнему создает нежелательный файл. –

+0

Спасибо. Я попытался использовать три выражения из' 'compestestring'' непосредственно в лямбда, и хотя бы он возвращал логическое значение, я получил ту же ошибку. –

ответ

1

Этот код:

long ndx[5]; 
for (int i = 0; i < 5; i++) ndx[i] = i + 1; 
std::sort(ndx[0], ndx[4], [&p](long i1, long i2) { comparestring((*p) + i1, (*p) + i2); }) 

должен быть:

long ndx[5]; 
for (int i = 0; i < 5; i++) ndx[i] = i; 
std::sort(ndx, ndx + 5, [&](long i1, long i2) { return comparestring(*(p + i1), *(p + i2)); } 

Первые два аргумента std::sort являются диапазоном итераторов. Это будет лучший стиль (если ваш компилятор совместим с C++ 11), используйте std::begin(ndx) и std::end(ndx).

Кроме того, вторая линия может быть записана std::iota(std::begin(ndx), std::end(ndx), 0);

+1

Большое спасибо. –

Смежные вопросы