我想知道std::visit返回类型转换应该如何工作.
上下文如下:我有一个变体对象,我想std::visit根据它的底层类型应用(通过)不同的函数.每个函数的结果可能有不同的类型,但我希望std :: visit将其打包为变体类型.
伪代码:
我有:
variant<A,B> obj
f(A) -> A
f(B) -> B
Run Code Online (Sandbox Code Playgroud)
我想要:
if obj is of type A => apply f(A) => resA of type A => pack it in variant<A,B>
if obj is of type B => apply f(B) => resB of type B => pack it in variant<A,B>
Run Code Online (Sandbox Code Playgroud)
现在,根据cppreference,std :: visit的返回类型是"所选访问者调用返回的值,转换为所有可能的std :: invoke表达式的公共类型"但是没有指定常见类型的含义.是std::common_type吗?在这种情况下,它不适用于gcc 7.2:
#include <variant>
#include <iostream>
#include <type_traits>
struct A {
int i;
};
struct B {
int j;
};
// the standard allows to specialize std::common_type
namespace std {
template<>
struct common_type<A,B> {
using type = std::variant<A,B>;
};
template<>
struct common_type<B,A> {
using type = std::variant<A,B>;
};
}
struct Functor {
auto
operator()(A a) -> A {
return {2*a.i};
}
auto
operator()(B b) -> B {
return {3*b.j};
}
};
int main() {
std::variant<A,B> var = A{42};
auto res = std::visit( Functor() , var ); // error: invalid conversion from 'std::__success_type<B>::type (*)(Functor&&, std::variant<A, B>&) {aka B (*)(Functor&&, std::variant<A, B>&)}' to 'A (*)(Functor&&, std::variant<A, B>&)' [-fpermissive]
}
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能表达这种解压 - 应用访问 - 重新包装模式?
笔记:
1)专业std::common_type<A(*)(Ts...),B(*)(Ts...)>不会削减它.这可以解决问题,但依赖于特定的std :: lib实现细节.此外,它不适用于多次访问.
2)我给出的例子实际上已经减少到最低限度,但你必须想象我想要提供的访问机制是在库侧,访问者是在客户端,可以是任意复杂的:未知数和参数类型,未知的返回类型.该库应该只提供访问和一组预定义的std::common_type专业化,用于访问返回类型.例如,定义
auto f = [](auto x) -> variant<A,B> { return Functor()(x); };
Run Code Online (Sandbox Code Playgroud)
然后应用std::visit到f是不是一个可行的选择:从库边,我不能在不知道"打包"返回类型预先定义这种拉姆达的.[主要的问题是,我认为无法询问std::common_type特定过载集的语言]
您可以创建自己的visit图层,例如:
template <typename Visitor, typename ... Ts>
decltype(auto) my_visit(Visitor&& vis, const std::variant<Ts...>& var)
{
return std::visit([&](auto&& e)
-> std::common_type_t<decltype(vis(std::declval<Ts>()))...>
{
return vis(e);
}, var);
}
Run Code Online (Sandbox Code Playgroud)