std::variant 的多态构造

Polymorphic construction of a std::variant

我想实现一个简单的错误 return 类型,即一种情况表示错误而另一种情况表示成功计算结果的变体。对于该任务,我想像这样创建错误构造函数:

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

template <typename A> using result_t = std::variant<int, A> ;

template <typename T> result_t<T> make_left_int()
{
    return 42;
}

int main ()
{
    result_t<double> a = make_left_int();
    result_t<void*> b = make_left_int();

    std::cout << std::get<int>(a) << std::endl << std::get<int>(b) << std::endl;
}

构造函数make_left_int是关于成功变量类型的多态性。但显然,C++ 编译器无法键入它。它无法推断(未使用的)模板参数 T。或者更确切地说,它无法将其与 doublevoid*.

统一起来

有没有办法实现这样的功能?

您可以让您的 make_left_int() return int,因为任何 result_t<T> 都可以从 int 构造。但是请注意,您可能会遇到 result_t<int> 的麻烦。

建议自己写一个result类型,不要依赖variant。这样做的好处是,您可以处理此类情况(具有 result<int>),并且它允许您以自己的方式在实际存储错误时处理对值的访问。

The constructor make_left_int ...

但是 make_left_int 不是 C++ 中的构造函数。与您可能使用其术语的函数式语言不同,C++ 构造函数是 class 的一种特殊方法,用于初始化 class 的实例。它不能是一个自由函数,它只是 returns class.

的一个实例

... polymorphic regarding the type of the success variant

是的,但是:C++ 模板类型推导仅对函数的参数 进行操作。例如,

template <typename T> T return_default() { return T{}; }

在此代码中不起作用,因为 return 类型不可用于推导类型参数 T:

int i = return_default();
double d = return_default();

尽管您仍然可以显式传递类型参数:

int i = return_default<int>();

最简单的解决方案是评论中提出的 _nh:从调用中推导出 return 类型,而不是相反(这避免了需要指定结果类型的地方相乘)

auto a = make_left_int<double>();

我怀疑指定成员的含义而不是它在记录中的位置也是更好的样式,例如

auto a = error_result<double>(42);

或者您可以使用实际的构造函数,用于您自己的变体样式 class,最好使用标记类型来区分错误代码和成功代码,以防成功结果也可以是 int:

result<double> a(Error{42});

注意。 C++ 中的 polymorphic 默认情况下通常被假定为 runtime 多态性,与此处讨论的 static/compile-time 多态性相反。如果您使用 template 关键字,您总是可以只说 template 并被理解。