c++ - 实现多类型算术运算符时如何解决“模板参数推导/替换失败”
问题描述
我似乎找不到正确的方法来实现它,这似乎是最接近正确的方法,但我得到一个模板参数推导错误。谁能指出我哪里出错了?
我正在尝试添加算术功能而std::variant
无需std::get
先:
#include <iostream>
#include <variant>
template<typename... Types>
class variant : public std::variant<Types...> {
private:
template <class Op, typename T, int index = 0>
decltype(auto) calc(const T& other) const {
if(sizeof...(Types) == 0 || index >= sizeof...(Types)){
return;
}
using ST = std::variant_alternative_t<index, std::variant<Types...>>;
if(std::holds_alternative<ST>(
std::variant<Types...>(*this)
)){
if(std::is_same<T, variant<Types...>>::value){
return Op()(std::get<ST>(*this), std::get<ST>(other));
}
else{
return Op()(std::get<ST>(*this), other);
}
}
return this->calc<Op, index+1>(other);
}
public:
using std::variant<Types...>::variant;
template <typename T>
decltype(auto) operator-(const T& other) const {
return this->calc<std::minus>(other);
}
// other operations will be added; std::plus, etc.
};
int main()
{
variant<int, double> vt1 = 2.3;
variant<int, double> vt2 = 5;
std::cout << "first: " << (vt1 - 2) << std::endl;
std::cout << "second: " << (vt2 - vt1) << std::endl;
return 0;
}
解决方案
你有几个问题:
std::minus
不是类型,而是模板。它不能绑定到class Op
. 您可能想std::minus<>
改用。- 当你打电话
calc<Op, index + 1>()
给calc<Op, index>()
你时,你会得到无限递归。开始的if
条件没有帮助,因为编译器仍然必须生成那个调用:这个条件是在运行时检查的,而不是在编译时检查的。你需要if constexpr
. decltype(auto)
返回类型的类型不一致。所有未丢弃的分支都应返回相同的类型。Op()(std::get<ST>(*this), std::get<ST>(other))
将抛出 if*this
并other
持有不同的类型(在您的示例中,它们确实持有不同的类型)。
std::visit
您可以简单地定义自由函数并std::visit
在实现中使用,而不是修复所有这些并重新发明:
namespace impl {
template<class T>
auto get_value(const T& t) {
return t;
}
template<class... Ts>
auto get_value(const std::variant<Ts...>& var) {
using T = std::common_type_t<Ts...>;
return std::visit([](T value) { return value; }, var);
}
template<class Op, class T, class U>
auto var_op(Op op, const T& t, const U& u) {
return op(get_value(t), get_value(u));
}
}
template<class... Ts, class U>
auto operator-(const std::variant<Ts...>& var, const U& u) {
return impl::var_op(std::minus<>{}, var, u);
}
template<class U, class... Ts>
auto operator-(const U& u, const std::variant<Ts...>& var) {
return impl::var_op(std::minus<>{}, u, var);
}
template<class... Ts, class... Us>
auto operator-(const std::variant<Ts...>& var1,
const std::variant<Us...>& var2) {
return impl::var_op(std::minus<>{}, var1, var2);
}
如果您想将这些函数限制为您自己的my_variant
派生自的类std::variant
,则需要get_value()
通过添加来修复static_cast
,因为使用了一些不专门用于的std::visit
帮助类(如) :std::variant_size
my_variant
template<class... Ts>
class my_variant : public std::variant<Ts...> {
public:
using std::variant<Ts...>::variant;
};
...
namespace impl {
template<class... Ts>
auto get_value(const my_variant<Ts...>& var) {
using T = std::common_type_t<Ts...>;
return std::visit([](T value) { return value; },
static_cast<const std::variant<Ts...>&>(var));
}
}
推荐阅读
- python - 无法从 aws 组织获取整个组织单位列表
- yaml - 无服务器错误:CloudFormation 模板无效:模板错误:Fn::GetAtt 实例引用未定义的资源名称角色
- php - WordPress中的页面特征图像问题
- python - 如何在不附加模块路径的情况下导入不同路径的模块?
- node.js - 如何创建旧版本的 Azure Web Bot?
- sql - 雪花视图 - 组语法编译错误
- flutter - 意外的 DropdownButtonFormField 行为
- javascript - 将事件添加到所有元素的正确方法是什么?
- python - 计划任务不会在 Windows 10 中为“运行用户是否登录”选项运行 .py 文件
- typescript - 如何编写 d.ts 声明文件以在 typescript 中导入默认类和命名导出?