提问人:newbie 提问时间:7/5/2023 更新时间:7/6/2023 访问量:104
如何连接两个基于元组的对象
How to concatenate two object which are based on tuple
问:
我有一个类模板,它基于一个并且仅由该元组组成。
如何连接此类模板的两个对象,以便将两个类的所有元组成员作为同一类模板的对象。
使用不起作用,可能是因为类型不是元组std::tuple
tuple_cat
template<typename...Ts>
class foo : private std::tuple<Ts...> {
public:
foo(Ts...vs) : std::tuple<Ts...>(vs...){}
// .
// .
// .
};
template<typename...T1s, typename...T2s>
foo<T1s..., T2s...> operator+(const foo<T1s...>& foo1, const foo<T2s...>& foo2){
// return std::tuple_cat(foo1, foo2); // this does not work
// what should be here?
}
foo<int, float, const char*> obj1(1, 1.23, "string1");
foo<const char*, float, int> obj2("string2" , 1.23, 1);
foo<int, float, const char*, const char*, float, int> obj3 = obj1 + obj2;// I want to do this by overloading of operator +
答:
您仍然可以通过使用 来实现此功能,但您还需要使用 。std::tuple_cat
std::apply
因为 的底座无法从外部访问,所以你有两种选择:tuple
foo
foo
正如 Nelfeal 在第一种方法中提到的,您可以声明 作为类模板的好友。operator+
foo
第二种方法要求您将任何其他类模板声明为友元类模板,这可能会使其他可能的方法更容易,这些方法涉及另一个 .并具有 as class 方法。foo
foo
operator+
template<typename...Ts>
class foo : private std::tuple<Ts...> {
template<typename ... T2s>
friend class foo;
public:
foo(Ts...vs) : std::tuple<Ts...>(vs...){}
template<typename ... T2s>
foo<Ts..., T2s...> operator+(const foo<T2s...>& other) const
{
const auto& base1 = *static_cast<const std::tuple<Ts ...> *>(this);
const auto& base2 = static_cast<const std::tuple<T2s ...>&>(other);
const auto& base = std::tuple_cat(base1, base2);
auto pass = [](auto&& ... refs){return foo<Ts..., T2s...>(std::move(refs) ...);};
return std::apply(pass, base);
}
// .
// .
// .
};
说明:
base1
和 只是 和 的基础。因为它们是 ,现在您可以使用它们来获得结果的串联基础。 将给定函数(第一个参数)应用于给定(第二个参数)的所有元素。lambda 函数只是根据给定的参数创建一个。base2
tuple
foo1
foo2
tuple
std::tuple_cat
tuple
std::apply
tuple
pass
foo
现在你可以像这样使用它:
foo<int, float, const char*> obj1(1, 1.23, "string1");
foo<const char*, float, int> obj2("string2" , 1.23, 1);
foo<int, float, const char*, const char*, float, int> obj3 = obj1 + obj2;
// or
auto obj4 = obj1 + obj2;
评论
operator+
friend
private
foo
explicit
foo
foo
std::tuple
std::tuple<Ts ...>(*this)
tuple
*this
因为你是私下继承的,所以 无法访问基数,所以你需要以一种或另一种方式修复它。我认为最简单的方法是交一个朋友。然后,通过添加 中的(私有)构造函数,您可以只在正确的类型上使用(通过引用或):std::tuple
operator+
operator+
foo
std::tuple
std::tuple_cat
static_cast
template<typename... Ts>
class foo : private std::tuple<Ts...> {
explicit foo(std::tuple<Ts...>&& tuple) : std::tuple<Ts...>(std::move(tuple)) {}
public:
foo(Ts...vs) : std::tuple<Ts...>(vs...){}
template<typename... T1s, typename... T2s>
friend foo<T1s..., T2s...> operator+(foo<T1s...> const& foo1, foo<T2s...> const& foo2);
};
template<typename... T1s, typename... T2s>
foo<T1s..., T2s...> operator+(foo<T1s...> const& foo1, foo<T2s...> const& foo2) {
std::tuple<T1s...> const& tuple1 = foo1;
std::tuple<T2s...> const& tuple2 = foo2;
return foo(std::tuple_cat(tuple1, tuple2));
}
如果不需要其他构造函数,可以使用将所有元素传递给主构造函数:std::apply
template<typename... T1s, typename... T2s>
foo<T1s..., T2s...> operator+(foo<T1s...> const& foo1, foo<T2s...> const& foo2) {
std::tuple<T1s...> const& tuple1 = foo1;
std::tuple<T2s...> const& tuple2 = foo2;
auto make_foo = [](auto&&... arg) { return foo(std::move(arg)...); };
return std::apply(make_foo, std::tuple_cat(tuple1, tuple2));
}
评论
std::tuple<int> tp{12}; foo foo1{std::move(tp)};
auto f1(){return 12;} auto f2(){return std::tuple{12, 13};} foo foo1 = f1(); foo foo2 = f2();
foo1
foo2
foo<std::tuple<int, int>>
explicit
评论
const std::tuple<Ts...> &me() const { return *this; }
tuple_cat
me()
operator+
auto
foo
std::tuple
foo
std::tuple
operator +
return std::tuple_cat(foo1.tuple_member, foo2.tuple_member);
std::tuple
foo
foo
Std::apply