首页 > 解决方案 > 转换移动构造函数的模板特化的 std::variant

问题描述

我正在使用一个封装模板专业化的 std::variant 的类,例如:

template<typename Type> struct Generic_node {...};
struct Leaf_node : Generic_node<...> {...};
struct Inner_node : Generic_node<...> {...};

struct Node {std::variant<Leaf_node, Inner_node> variant_;};

我正在尝试使用转换移动构造Node函数从函数构造一个Generic_node,但编译失败。

我定义了一个模板构造函数,它接受一个右值引用(假设是一个专门的类)并通过将值移动到变体来构造变体,我希望在其中调用转换移动构造函数# (4)

当我试图创建最小的非工作示例时,我发现问题实际上只从模板函数中显示出来,如果我知道确切的类型(Leaf_node == Generic_node<...>编译器知道),移动构造就会成功。因此,我假设总是会发生一些我没有预料到的模板魔术。

#include <variant>

template<typename T>
struct Base
{
    void f();
};

struct Derived : Base<int> {};

struct Variant
{
    // In real program expecting the T to be one of the multiple variants
    // Here I use only one variant because it suffices to illustrate the problem
    template<typename T>
    Variant(T&& t)
        :
        variant_ {std::move(t)}
    {
    }

    std::variant<Derived> variant_;
};

template<typename T>
void
Base<T>::
f()
{
    Variant {std::move(Derived {})}; // can call on  exact type
    Variant {std::move(Base<T> {})}; // can not call on specialized template type
}

int
main()
{
    Derived {}.f();
}

相关编译器错误消息(clang 7,libstdc++-8):

note: candidate template ignored: substitution failure [with _Tp = Base<int>,
$1 = void, $2 = void]: implicit instantiation of undefined template
'std::variant<Derived>::__to_type_impl<18446744073709551615, false>'
variant(_Tp&& __t)

该问题很可能与变体无关,而是与 Variant 构造函数的模板实例化中的相等性有关Base<T> == Derived,编译器好像没有看到。

模板实例化中发生了什么,为什么编译器不能调用提供的构造函数?

编辑:因为我打算创建一个专业化,我忘记了继承不能暗示类类型相等,即使它在技术上是在这种特殊情况下。因此,从专门的 Base 构造 Derived by move 是一项简单的任务:

struct Derived : Base<int>
{
    Derived() = default;
    Derived(Base<int>&&) {}
};

如果我是正确的,则需要为 Base 的每个派生类显式定义构造函数。

标签: c++constructormovevariant

解决方案


在您给出的示例中,Derived 类是与 Base 分开的类。它们具有完全相同的成员、相同的方法,但它们仍然是独立的类。

解决它的最简单方法是使用using语句而不是将其声明为单独的类:

using Derived = Base<int>;

推荐阅读