Я пытаюсь выполнить очень простую абстрактную фабрику с шаблонизированными аргументами и получаю сообщение об ошибке, до которого не могу добраться.
Основная проблема заключается в том, что за пределами шаблона вариантный тип принимает любого из членов своего объединения, но внутри шаблона это выведение кажется ошибочным. Я не могу найти ошибка в моей конструкции, которая приводит к этому.
Минимальный производящий код выглядит следующим образом; просто удаляя шаблоны, он прекрасно компилируется
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;
}
Как написано, однако, он выдает ошибку компиляции
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
Я считаю, что проблема не является проблемой lvalue / rvalue, подобной этому вопросу , поскольку метод, на который ссылаются, является статическим (но мы можем вытащить его и заставить его быть lvalue, не решая это ошибка тоже). GCC, как известно, имеет некоторые ошибки с псевдонимами , но я не понимаю, как они здесь будут актуальны, так как я думаю, что они изолированы от variadics; Я использую g ++ - 7.1, -std = c ++ 17
Почему компилятор не может принимать тип A
там, где запрашивается тип variant<A,B>
? Не в этом ли смысл вариантов? Например, AB ab = A();
или AB ab = B();
оба допустимы, хотя это может быть просто умной перегрузкой оператора =
?
Я неправильно использую вариант, std :: function, templates, aliases или все вышеперечисленное?
В качестве доказательства того, что проблема связана с шаблонами, код без шаблонов компилируется как:
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;
}
Моим основанием полагать, что вариант std может заменить любой из отдельных типов, является тривиальный тест
AB ab1 = A();
ab1 = B();
оба кажутся приемлемыми.