c++ - 重载 std::tuple 的类型转换运算符
问题描述
序言:嘿,假设我有各种数据表示,我想以任意到任意的方式在它们之间无缝转换。这些陈述是我无法控制的。我的实际示例是 3D 中的面向对象:我们有四元数、欧拉角、角轴和旋转矩阵,以及来自不同库(我必须使用)的各种类中的所有内容。为此,我构建了一个代理类,它将值存储在一个特定的表示中,并且可以通过重载的构造函数将其转换为它,并通过重载的类型转换运算符将其转换出来,就像这样:
Eigen::Quaterniond eig_quaternion = AttitudeConvertor(roll, pitch, yaw);
tf2::Quaternion tf2_quaternion = AttitudeConvertor(eig_quaternion);
问题:到目前为止,一切都很好,直到我想将类型转换重载到std::tuple,这很方便,例如,在返回yaw、pitch和roll角度时,看起来像这样:
auto [roll2, pitch2, yaw2] = AttitudeConvertor(tf2_quaternion);
该类可以编译,但分配给auto [a, b, c]
并且std::tie(a, b, c)
不起作用。可以通过返回元组的专用函数的形式进行解决方法。或者通过创建一个自定义类来存储三个双打。这些工作正常,但不再那么无缝了。
我知道函数的返回类型不能重载。这就是我创建这个代理类的原因。但是还有其他方法可以返回元组吗?即使它只是元组的一个变体?还是我应该以不同的方式解决这个问题?
我准备了一个以简单数字转换为主题的最小(非)工作示例:
#include <iostream>
#include <math.h>
#include <tuple>
using namespace std;
class NumberConvertor {
public:
// | ---------------------- constructors ---------------------- |
NumberConvertor(const int& in) {
value_ = double(in);
}
NumberConvertor(const double& in) : value_(in){};
// | ------------------- typecast operators ------------------- |
operator int() const {
return int(value_);
}
operator double() const {
return value_;
}
// return the integer and the fractional part
operator std::tuple<int, double>() const {
int int_part = floor(value_);
double frac_part = fmod(value_, int_part);
return std::tuple(int_part, frac_part);
}
// | ------------------------ functions ----------------------- |
// the workaround
std::tuple<int, double> getIntFrac(void) const {
int int_part = floor(value_);
double frac_part = fmod(value_, int_part);
return std::tuple(int_part, frac_part);
}
private:
double value_; // the internally stored value in the 'universal representation'
};
int main(int argc, char** argv) {
// this works just fine
int intval = NumberConvertor(3.14);
double fracval = NumberConvertor(intval);
cout << "intval: " << intval << ", fracval: " << fracval << endl;
// this does not compile
// auto [int_part, frac_part] = NumberConvertor(3.14);
// neither does this
// int a;
// double b;
// std::tie(a, b) = NumberConvertor(3.14);
// the workaround
auto [int_part2, frac_part2] = NumberConvertor(3.14).getIntFrac();
cout << "decimal and fractional parts: " << int_part2 << ", " << frac_part2 << endl;
std::tie(int_part2, frac_part2) = NumberConvertor(1.618).getIntFrac();
cout << "decimal and fractional parts: " << int_part2 << ", " << frac_part2 << endl;
return 0;
};
生成文件:
main: main.cpp
g++ -std=c++17 main.cpp -o main
all: main
预期输出:
intval: 3, fracval: 3
decimal and fractional parts: 3, 0.14
decimal and fractional parts: 1, 0.618
解决方案
Jarod42s 对binding_a_tuple-like_type 的提示让我想出了以下内容。
我基本上让你的NumberConvertor
行为像一个元组。
using as_tuple_type = std::tuple<int,double>;
为方便起见,可以使用别名模板:
template <size_t i>
using nth_type = typename std::tuple_element_t<i,as_tuple_type>;
使用它,我们可以提供一个get
方法:
struct NumberConvertor {
NumberConvertor(const int& in) : value_(in) {}
NumberConvertor(const double& in) : value_(in) {};
template <size_t i> nth_type<i> get();
private:
double value_;
};
template <> nth_type<0> NumberConvertor::get<0>() { return value_;}
template <> nth_type<1> NumberConvertor::get<1>() { return value_;}
这里并不真正需要专业化,但我想对于实际情况并非如此。
std::tuple_size
最后,我们为和提供专业化std::tuple_element
:
template <>
struct std::tuple_size<NumberConvertor> : std::tuple_size<as_tuple_type>
{};
template <size_t i>
struct std::tuple_element<i,NumberConvertor> : std::tuple_element<i,as_tuple_type>
{};
现在这将起作用:
int main(int argc, char** argv) {
auto [int_part, frac_part] = NumberConvertor(3.14);
std::cout << int_part << " " << frac_part;
};
推荐阅读
- python - 获取列表中重复元素的单个索引号
- javascript - 尝试将 SHA-1 摘要从 Python 移植到浏览器 JavaScript 的不同结果
- javascript - 等待计数器达到角度值
- python - 更改 pandas.DataFrame 中的值
- ruby - Ruby on Rails - Criteria - Mongoid - where 条件为 2 x 2 列
- javascript - 仅检索 javascript 数组的列
- log-likelihood - 问题根本不需要帮助
- service-worker - 服务工作者失败 NTLM 身份验证并出现 504 错误
- java - 如何阻止 X 和 O 相互覆盖 TicTacToe java?
- javascript - 赛普拉斯不会自动滚动