我有以下情况:我必须将多个指针和一个标识符打包到如下的元组中:
typedef tuple<unsigned*, unsigned*, unsigned*, unsigned> tuple_with_pointers_t;
这里我有三个指针和一个标识符。在其他情况下,我可能会有更多或更少的指针,但最后一个指针将是标识符。请注意,我仅使用 unsigned*
作为示例。实际上,它可能是更复杂的对象。
现在,我想比较两个这样的元组的值。也就是说,我需要解除引用除了最后一个以外的所有元素。我们可以使用以下方法(在 C++17 中)实现:
template <size_t I = 0, typename T, typename... Ts>
constexpr bool lesser(std::tuple<T, Ts...> a, std::tuple<T, Ts...> b)
{
if constexpr (I < sizeof...(Ts))
return (*std::get<I>(a) < *std::get<I>(b)) ||
((*std::get<I>(a) == *std::get<I>(b)) && lesser<I + 1>(a, b));
else
return std::get<I>(a) < std::get<I>(b);
}
这种构造方法在比较两个元组时非常有效。现在,我想将
lesser()
作为一个函数对象用于std::sort()
中。但是,g++和clang++都报错“couldn't infer template argument '_Compare'”。换句话说,我们需要向lesser传递正确的模板参数。我尝试了一些方法,但没有成功:我们有三个模板参数,我不确定如何在此处使用元组中的
_Elements
。什么策略最好呢?以下是一些示例代码:
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
// My weird tuple with pointers and one unsigned index.
typedef tuple<unsigned*, unsigned*, unsigned*, unsigned> tuple_with_pointers_t;
// This works fine for two tuples directly. Note that we cannot dereference
// the last tuple element, so we compare it directly.
template <size_t I = 0, typename T, typename... Ts>
constexpr bool lesser(std::tuple<T, Ts...> a, std::tuple<T, Ts...> b)
{
if constexpr (I < sizeof...(Ts))
return (*std::get<I>(a) < *std::get<I>(b)) ||
((*std::get<I>(a) == *std::get<I>(b)) && lesser<I + 1>(a, b));
else
return std::get<I>(a) < std::get<I>(b);
}
int main() {
// Three sets of values.
vector<unsigned> values1 {1, 2, 3};
vector<unsigned> values2 {10, 20, 30};
vector<unsigned> values3 {11, 22, 33};
// Here, we pack it all together with the index.
vector<tuple_with_pointers_t> all;
for(unsigned i = 0; i < values1.size(); ++i)
all.emplace_back(&values1[i], &values2[i], &values3[i], i);
// So, it works if we want to compare two elements of our vector.
cout << "\n- t0 < t1: " << std::boolalpha << lesser(all[0], all[1]);
cout << "\n- t2 < t1: " << std::boolalpha << lesser(all[2], all[1]);
// Now, I want to sort the tuples by their values. The compiler doesn't
// like it: it cannot deduce the template parameters.
sort(all.begin(), all.end(), lesser);
return 0;
}
我很感激任何C++17或C++20方面的帮助,但我正在寻找最简洁优雅的方法来解决这个问题。如果可能的话,可以直接在sort()
调用中使用lambda函数。
谢谢!
更新:
好的,我找到了一个小技巧,它能够实现:
sort(all.begin(), all.end(),
[](const auto &a, const auto &b) {
return lesser(a, b);
}
);
基本上,我们将其包装成 lambda 表达式,因此编译器可以推断类型。但是,我们能做得更好吗?
谢谢
lesser
的实例化,而不仅仅是将模板名称插入其中。例如,sort(all.begin(), all.end(), lesser<0, unsigned*, unsigned*, unsigned*, unsigned>())
。您可以通过使用typedef
(或等效的using
)来简化此过程。 - Peteroperator()
的函数对象中。 - n. m.operator<
就可以胜任(您还可以比较等效元素的 id)。 (对于std::map
,这确实会有问题,因为在地图中您也会有“重复”的元素)。 - Jarod42