Kri*_*mbe 4 c++ templates virtual-functions variant strong-typedef
在工作中,我遇到了一种情况,描述函数返回的结果的最佳类型是std::variant<uint64_t, uint64_t>- 当然,这不是有效的 C++,因为你不能有两个相同类型的变体。我可以将其表示为 a std::pair<bool, uint64_t>,或者该对的第一个元素是枚举,但这是一个特殊情况;astd::variant<uint64_t, uint64_t, bool>不是那么容易表示,我的函数式编程背景真的让我想要Either- 所以我去尝试实现它,使用访问者模式,因为我已经能够在没有对和类型的本机支持的其他语言中做到这一点:
template <typename A, typename B, typename C>
class EitherVisitor {
virtual C onLeft(const A& left) = 0;
virtual C onRight(const B& right) = 0;
};
template <typename A, typename B>
class Either {
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) = 0;
};
template <typename A, typename B>
class Left: Either<A, B> {
private:
A value;
public:
Left(const A& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onLeft(value);
}
};
template <typename A, typename B>
class Right: Either<A, B> {
private:
B value;
public:
Right(const B& valueIn): value(valueIn) {}
template <typename C>
virtual C Accept(EitherVisitor<A, B, C> visitor) {
return visitor.onRight(value);
}
};
Run Code Online (Sandbox Code Playgroud)
C++ 拒绝这样做,因为模板方法Accept不能是虚拟的。是否有解决此限制的方法,这将允许我根据其 f 代数和变形来正确表示基本和类型?
也许最简单的解决方案是T为Rightand使用轻量级包装器Left?基本上是一个强类型别名(也可以使用 Boost 的强 typedef)
template<class T>
struct Left
{
T val;
};
template<class T>
struct Right
{
T val;
};
Run Code Online (Sandbox Code Playgroud)
然后我们可以区分它们进行访问:
template<class T, class U>
using Either = std::variant<Left<T>, Right<U>>;
Either<int, int> TrySomething()
{
if (rand() % 2 == 0) // get off my case about rand(), I know it's bad
return Left<int>{0};
else
return Right<int>{0};
}
struct visitor
{
template<class T>
void operator()(const Left<T>& val_wrapper)
{
std::cout << "Success! Value is: " << val_wrapper.val << std::endl;
}
template<class T>
void operator()(const Right<T>& val_wrapper)
{
std::cout << "Failure! Value is: " << val_wrapper.val << std::endl;
}
};
int main()
{
visitor v;
for (size_t i = 0; i < 10; ++i)
{
auto res = TrySomething();
std::visit(v, res);
}
}
Run Code Online (Sandbox Code Playgroud)