首页 > 解决方案 > 让类继承模板类型的构造函数

问题描述

我创建了以下类来创建任何类型的值,这些值在每次使用调用运算符时都是固定的或重新计算的:

template <typename T>
class DynamicValue {
    private:
    std::variant<T, std::function<T()>> getter;

    public:
    DynamicValue(const T& constant) : getter(constant){};
    template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
    DynamicValue(F&& function) : getter(function) {}
    DynamicValue(const T* pointer) : DynamicValue([pointer]() { return *pointer; }) {}
    DynamicValue(const DynamicValue& value) : getter(value.getter) {}
    ~DynamicValue() {}
    DynamicValue& operator=(const DynamicValue& value) {
        getter = value.getter;
        return *this;
    }
    T operator()() {
        return getter.index() == 0 ? std::get<T>(getter) : std::get<std::function<T()>>(getter)();
    }
};

我还编写了以下虚拟结构来展示我的问题:

struct A {
    int b;
};

问题是,理想情况下,我可以初始化 any DynamicValue<T>,就好像它是 type 一样T。所以,在这个例子中,因为我可以做A a = {1};,而不是必须写DynamicValue<A> a = A{1};,我可以做DynamicValue<A> a = {1};。但是,当我尝试这样做时,出现以下错误:

无法将“{1}”从“”转换为“DynamicValue”

你可以在这里尝试一个活生生的例子。

无论如何要克服这个问题还是我必须接受更长的语法?

标签: c++templatesconstructor

解决方案


您可以添加一个构造函数,该构造函数接受类型所需的所有参数T并将它们转发给构造函数T并初始化您的内部值getter

只需将以下行添加到您的类中:

template < typename ... S> DynamicValue( S&& ... parms ): getter{T{ std::forward<S...>( parms... )}} {}

但!如果我们这样做,如果我们传递一个非 const DynamicValue,它也会被调用。所以我们必须通过 SFINAE 排除它并得到:

template <typename F,
   typename = std::enable_if_t<std::is_invocable_v<F>&&    !std::is_same_v<std::remove_reference_t<F>, DynamicValue<T>>, bool>>
            DynamicValue(F&& function) : getter(function) {}

但是还有一个问题:

您的代码已经有一些东西可以作为不想要的复制构造函数调用!

构造函数:

template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>>>
    DynamicValue(F&& function) : getter(function) {}

也将被调用,因为也是可调用的DynamicType<T>!我们还必须使用第二个条件来禁用类型的实例化,DynamicType<T>这会导致:

template <typename F, typename = std::enable_if_t<std::is_invocable_v<F>&& !std::is_same_v<std::remove_reference_t<F>, DynamicValue<T>>, bool>>
            DynamicValue(F&& function) : getter(function) {}

您可以创建一个实例:

DynamicValue<A> a1 = A{1};
DynamicValue<A> a2{1};

使用= {1}将不起作用。

现在甚至片段

DynamicValue<A> a9{100};
DynamicValue<A> a10(a9);
std::cout << a10().b << std::endl;

按预期工作。


推荐阅读