c++ - 从可变参数继承并使用参数包: default constructor构造

标签 c++ templates crtp parameter-pack

我有该代码:

template<typename Type, typename... Extentions>
class Variable : virtual public GenericVar<Type>, public Extentions...
{
        static_assert((std::is_base_of_v<GenericVar<Type>, Extentions> && ...), "Only virtual base of GenericVar<T> allowed as variadic.");

    public:
        template<typename... Args>
        Variable(Type initValue, Args... args);
        virtual ~Variable();
};

template<typename Type, typename... Extentions>
template<typename... Args>
Variable<Type,Extentions...>::Variable(Type initValue, Args... args) : GenericVar<Type>(), Extentions(args)...
{
    this->value = initValue;
}

template<typename Type, typename... Extentions>
Variable<Type,Extentions...>::~Variable()
{

}

用法:


template<typename T>
using Constant = Variable<T, Immutable<T>, Forceable<T>>;

int main(int argc, char *argv[])
{

    Variable<float, Forceable<float>> test2(1.2f,nullptr);
    Constant<float> constant(4.578f, nullptr, nullptr);
    Variable<quint32, Forceable<quint32>, ChangeCheckable<quint32>> value(45, nullptr, nullptr);
}

我想创建一个通用的、可扩展的类来构建我的所有 var 类型。
而且效果很好!但是...

我还没有找到避免构造函数中 nullptr 的方法。例如“强制”:

template<typename T>
class Forceable : virtual public GenericVar<T>
{
    public:
        Forceable(std::nullptr_t);
        ...
        ...
};

template<typename T>
Forceable<T>::Forceable(std::nullptr_t)
{
    this->forced = false;
}

如果我删除它,我会收到此错误:

xxxxxxxxxxxxxxxx\main.cpp:16: erreur : mismatched argument pack lengths while expanding 'Extentions'
In file included from xxxxxxxxxxxxxxxx/Variables/Extention/Detectable.h:6,
                 from xxxxxxxxxxxxxxxx\main.cpp:5:
xxxxxxxxxxxxxxxx/Variables/Variable.h: In instantiation of 'Variable<Type, Extentions>::Variable(Type, Args ...) [with Args = {}; Type = float; Extentions = {Forceable<float>}]':
xxxxxxxxxxxxxxxx\main.cpp:16:49:   required from here
xxxxxxxxxxxxxxxx/Variables/Variable.h:22:108: error: mismatched argument pack lengths while expanding 'Extentions'
   22 | Variable<Type,Extentions...>::Variable(Type initValue, Args... args) : GenericVar<Type>(), Extentions(args)...
      |                                                                                                            ^~~

因为:在这种情况下,我猜是“Extentions(args)...”而不是“Extentions()” 我认为有一个解决方案......但我还没有找到它!

我想要:


template<typename T>
using Constant = Variable<T, Immutable<T>, Forceable<T>>;

int main(int argc, char *argv[])
{

    Variable<float, Forceable<float>> test2(1.2f);
    Constant<float> constant(4.578f);
    Variable<quint32, Forceable<int>, ChangeCheckable<int>> value(45);
}

更深入的示例:

Variable<int, Forceable<int>, Boundable<int,int>, ChangeCheckable<int>, Validable<int>, RiseDefault<int, bool, Riseable> > 
            value3(0, nullptr, {-30,50}, nullptr, nullptr, 40, new Variable<bool, Riseable>(false,nullptr));

最佳答案

您可以为 Variable 创建一个构造函数,它将前 N 个 Extension 作为参数,并默认构造其余的。

这是一个不一定漂亮的实现

#include <tuple>

template <typename... T>
struct Variable: T... {
    template <typename... U, size_t NumMissing = sizeof...(T) - sizeof...(U)>
    Variable(U&&... u): Variable(std::make_index_sequence<NumMissing>{}, std::forward<U>(u)...) {}
    
private:
    struct PrivateTag {};
    
    template <typename... U, size_t... I>
    Variable(std::index_sequence<I...>, U&&... u):
        Variable(PrivateTag{},
                 std::forward<U>(u)...,
                 std::tuple_element_t<sizeof...(U) + I, std::tuple<T...>>()...) {}
    
    template <typename... U>
    Variable(PrivateTag, U&&... u): T(std::forward<U>(u))... {
        static_assert(sizeof...(U) == sizeof...(T));
    }
};

和测试代码

struct Ext {
    Ext(int = 0) {}
};

struct Ext2 {
    explicit Ext2(float = 0.0f) {}
};

// Extension that takes multiple constructor arguments
struct Ext3 {
    explicit Ext3(int, int) {}
};

int main() {
    // Default constructs both extensions
    Variable<Ext, Ext2> x;

    // Constructs Ext with value 1 and default constructs Ext2
    Variable<Ext, Ext2> y(1);

    // Constructs Ext with value 1 and Ext2 with value 1.f
    Variable<Ext, Ext2> z(1, 1.f);

    // Explicitly construct Ext3 since it takes multiple constructor aguments
    Variable<Ext, Ext3> z(0, Ext3(1, 2));
}

此行为符合默认函数参数的工作方式。

关于c++ - 从可变参数继承并使用参数包: default constructor构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76797899/

相关文章:

c++ - 如何将 const ref 返回给结构对象,使其所有嵌套结构也都是只读的?

templates - 在 PyCharm 中将文件夹标记为模板文件夹有什么影响?

c++ - 我可以将 CRTP 与虚函数或仿函数一起用于访问者算法以容忍类的更改吗

c++ - 在表达式模板中嵌套子表达式

c++ - CRTP 静态多态性 : Using the Base Class to Call Derived Methods

c++ - 如何将字符串转换为字符矩阵

c++ - unsigned short 和 signed short 比较奇怪的行为

c++ - C 函数 **ntohl** 给出链接器错误(未解析的外部)

c++ - 使用模板进行递归类型向上转换

在我的用户定义类型上使用 boost::get 的 C++ Boost::variant 错误