将索引数组排序为主数组
Sort Array of Indexes Into Primary Array
我正在编写一个 C++ dll 来对从 VBA 传递的 SAFEARRAY 进行排序。
我没有使用任何 OLE 库,而是直接访问数组描述符和数据。
我可以毫无问题地对任何原生 VBA 类型的数组进行排序。例如,以下片段对 BSTR 数组进行排序:
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 字符串的有效负载中包含零字符并不常见,因此我没意见。以上效果很好。
问题
我希望 dll 能够选择性地将索引的伴随数组排序到主数据数组中。在这种模式下,只有索引数组会被排序,源数据保持不变。
我的研究表明,lamda 仿函数可能是最有前途的途径,因为我不希望为额外的数组或数据向量或对分配内存。
特别是this answer seems very promising.
但是,我不知道如何使它适应我正在处理指向从 pData 开始的 BSTR 的原始指针的情况。
我试过以下方法:
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++ 的存在),所以我有点挣扎。感谢任何帮助。
更新
代码现在看起来是这样的..它编译了,但是执行后 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); })
此代码:
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
的前两个参数是迭代器范围。使用 std::begin(ndx)
和 std::end(ndx)
.
会更好(假设您的编译器与 C++11 兼容)
还有,第二行可以写成std::iota( std::begin(ndx), std::end(ndx), 0 );
我正在编写一个 C++ dll 来对从 VBA 传递的 SAFEARRAY 进行排序。
我没有使用任何 OLE 库,而是直接访问数组描述符和数据。
我可以毫无问题地对任何原生 VBA 类型的数组进行排序。例如,以下片段对 BSTR 数组进行排序:
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 字符串的有效负载中包含零字符并不常见,因此我没意见。以上效果很好。
问题
我希望 dll 能够选择性地将索引的伴随数组排序到主数据数组中。在这种模式下,只有索引数组会被排序,源数据保持不变。
我的研究表明,lamda 仿函数可能是最有前途的途径,因为我不希望为额外的数组或数据向量或对分配内存。
特别是this answer seems very promising.
但是,我不知道如何使它适应我正在处理指向从 pData 开始的 BSTR 的原始指针的情况。
我试过以下方法:
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++ 的存在),所以我有点挣扎。感谢任何帮助。
更新
代码现在看起来是这样的..它编译了,但是执行后 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); })
此代码:
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
的前两个参数是迭代器范围。使用 std::begin(ndx)
和 std::end(ndx)
.
还有,第二行可以写成std::iota( std::begin(ndx), std::end(ndx), 0 );