使用变体时,不接受模板化的孩子作为父母

时间:2019-06-11 04:57:11

标签: c++ templates variant

我正在尝试使用模板化的参数执行一个非常简单的抽象工厂,并且收到一个我无法理解的错误。

核心问题是,在模板之外,变量类型接受其联合的任何成员,但是在模板内部,这种推论似乎失败了。在我的构造中找到导致这种情况的错误。

最小产生代码如下:只需删除模板,就可以编译

code 1006

但是,如所写,它会吐出编译错误

class A{};
class B{};

using AB = std::variant<A,B>;

template <class T1, class T2>
class Parent
{
};

class Child : public Parent<A,B>
{
public:
    static Parent<A,B>* build(){ return new Child(); }
};


template <class T1, class T2>
using Fn = std::function<Parent<T1,T2> *(void)>;

using ParentFn = Fn<AB,AB>;

int main()
{
        // in a factory, we might say
        // map<string, ParentFn> m; m["key"] = &Child::build;
        // but for MRE I'll just do assignment
        ParentFn tmp = &Child::build; // does just fine without templates, crashes horribly with

    return 0;
}

我认为问题不是an lvalue/rvalue issue like this question,因为所引用的方法是静态的(但我们也可以将其拔出并强制为左值,而无需解决此错误)。 GCC is known to have some bugs with aliases,但我在这里看不到它们的相关性,因为我认为它们与变量无关。我正在使用g ++-7.1,-std = c ++ 17

在请求类型为main.cpp:32:24: error: conversion from ‘Parent<A, B>* (*)()’ to non-scalar type ‘ParentFn {aka std::function<Parent<std::variant<A, B>, std::variant<A, B> >*()>}’ requested ParentFn tmp = &Child::build; // does just fine without templates, crashes horribly with 的情况下,编译器为什么不能接受类型A?这不是变体的全部内容吗?例如,variant<A,B>AB ab = A();都有效,尽管这可能只是AB ab = B();运算符的聪明重载?

我是否滥用变量,std :: function,模板,别名或以上所有内容?


为证明问题与模板有关,没有模板的代码编译为:

=

我认为std变体可以替代任何一种单独类型的依据是微不足道的测试

class Parent
{
};

class Child : public Parent
{
public:
    static Parent* build(){ return new Child(); }
};

using Fn = std::function<Parent *(void)>;

using ParentFn = Fn;

int main()
{
        ParentFn tmp = &Child::build; // does just fine without templates, crashes horribly with

    return 0;
}

两者都可以接受。

1 个答案:

答案 0 :(得分:2)

模糊化代码,我认为您要尝试执行的操作归结为尝试以​​下操作。

作品

#include <variant>

class A{};
class B{};

using AB = std::variant<A,B>;


AB * Foo();

typedef AB*(*Fn)();

int main()
{
    Fn f = &Foo;

}

不起作用

#include <variant>

class A{};
class B{};

using AB = std::variant<A,B>;


AB * Foo();

typedef A*(*Fn)();

int main()
{
    Fn f = &Foo;

}
  

错误:从'AB *()()'{aka'std :: variant )()'}到'Fn'{aka'A (*)()'} [-fpermissive]

如果您想进一步减少它,则尝试将std::variant<A,B> *转换为A*,这将不起作用。

实际上,您甚至无法将A*转换为std::variant<A,B> *。唯一允许的转换是Astd::variant<A,B>Bstd::variant<A,B>

https://godbolt.org/z/Xwbsou