gpt4 book ai didi

c++ - 通过 std::visit 从 std::variant 中的可能类型返回值

转载 作者:行者123 更新时间:2023-12-03 11:14:58 30 4
gpt4 key购买 nike

我想把我的头绕在std::variantstd::visit我试图想出一种方法来指定我希望我的变量保存的几种类型(它们将进入我的 std::variant),然后通过 std::visit 检索存储的数据.考虑以下示例:

#include <iostream>
#include <variant>
#include <string>

struct PrintType {
void operator()(const int &data) {
std::cout << "visiting int node" << std::endl;
}
void operator()(const double &data) {
std::cout << "visiting double node" << std::endl;
}
};

struct SingleOperatorOverload {
int operator()(const int &data) {
std::cout << "visiting int node" << std::endl;
return data;
}
};

struct AllTypesOperatorOverload {
int operator()(const int &data) {
std::cout << "visiting int node" << std::endl;
return data;
}
double operator()(const double &data) {
std::cout << "visiting double node" << std::endl;
return data;
}
};

int main() {

using var_t = std::variant<int, double>;

// print int related operator() content, OK
var_t foo = 42;
std::visit(PrintType(), foo);

// print double related operator() content, OK
foo = 3.1415;
std::visit(PrintType(), foo);

// get value and store into bar, struct with single operator(), OK
foo = 42;
auto bar = std::visit(SingleOperatorOverload(), foo);
std::cout << "bar: " << bar << std::endl;

// get value and store into bar, struct with multiple operator(), ERROR
auto bar = std::visit(AllTypesOperatorOverload(), foo);
std::cout << "bar: " << bar << std::endl;

return 0;
}
允许变体持有(在这个简化的例子中) intdouble .如果我只想根据类型打印一些东西(如 PrintType 结构所做的那样),那工作正常。
如果我想通过访问者检索数据,就像在 SingleOperatorOverload 中所做的那样类,仅提供 operator() 的实现接受一个 int 作为参数,这是可行的。但是,一旦我尝试实现 operator()对于 std::variant 中的每种类型,即这里 intdouble ,如 AllTypesOperatorOverload struct,我收到编译错误 error: invalid conversion from '...' {aka double ...} to '...' {aka int ...}好像是 std::variant处理函数签名的方式不同吗?
我试过 SFINAE 但这似乎并没有缓解问题
struct AllTypesOperatorOverload {
template<typename T, std::enable_if_t<std::is_same<T, int>::value>>
T operator()(const T &data) {
std::cout << "visiting int node" << std::endl;
return data;
}
template<typename T, std::enable_if_t<std::is_same<T, double>::value>>
T operator()(const T &data) {
std::cout << "visiting double node" << std::endl;
return data;
}
};
现在将报告 error: no type named 'type' in 'struct std::invoke_result<AllTypesOperatorOverload, int&>' .有没有办法提供 operator()对于所有类型,然后将它们各自的值接收到 bar 中使用正确的类型取决于如何 foo已经设置好了?我知道 std::get_if<T>()这可能在这里有用,但理想情况下,除非绝对必要,否则我不希望对每种类型进行长时间的 if 语句检查(这是一个简化示例,我可能希望在 std::variant 中有更多类型) .

最佳答案

错误消息很糟糕,但这里的问题是所有变体的替代品在访问者中必须具有相同的返回类型。您的 AllTypesOperatorOverload不遵守此规则,返回 double和一个 int ,它们不是同一类型。
libstdc++ or any version of libc++ produce much better error messages的最新版本明确地告诉你这一点(以下是我包装的词):

error: static_assert failed due to requirement '__visit_rettypes_match'
"std::visit requires the visitor to have the same return type for
all alternatives of a variant"
static_assert(__visit_rettypes_match,

这是有道理的,因为当您查看这一行时, bar 的类型是什么? ?
auto bar = std::visit(AllTypesOperatorOverload(), foo);
如果你被允许返回不同的类型, bar的类型取决于哪个替代 foo在运行时保持。这在 C++ 中是行不通的。

请注意,有更简单的方法可以为 std::visit 创建访问者使用 lambdas 而不是外部定义的结构。您可以使用 if constexpr :
std::visit([](auto value) {
if constexpr (std::is_same_v<int, decltype(value)>) {
std::cout << "visiting int\n";
} else {
static_assert(std::is_same_v<double, decltype(value)>);
std::cout << "visiting double\n";
}
std::cout << "bar: " << value << '\n';
}, foo);
或者,您可以定义一个 overloaded可以让您重载 lambda 的辅助结构:
template <typename... Lambdas>
struct overloaded : Lambdas...
{
template <typename... Fns>
explicit constexpr overloaded(Fns&&... fns)
: Lambdas(std::forward<Fns>(fns))...
{}

using Lambdas::operator()...;
};
template <typename... Lambdas>
overloaded(Lambdas...) -> overloaded<Lambdas...>;

// Usage:
std::visit(overloaded{
[](int value) {
std::cout << "visiting int\n";
std::cout << "bar: " << value << '\n';
},
[](double value) {
std::cout << "visiting double\n";
std::cout << "bar: " << value << '\n';
}
}, foo);

关于c++ - 通过 std::visit 从 std::variant 中的可能类型返回值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66128167/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com