可变参数模板回调接口类实例化不能重载

时间:2019-07-16 09:44:52

标签: c++ interface callback embedded variadic-templates

我要做的是仅具有一个函数成员的回调接口。 今天,我有2个最终类,它们使用此接口通过将特定的回调保存在CallbackStore中来定义其行为。

通过约束(here),我实现了以下最小限度的编译代码,但仅使用一个子类:

#include <iostream>
#include <stdint.h>

using namespace std;

static constexpr int STORE_SIZE = 4;

void* operator new(size_t size)
{
    cout << "ERROR HEAP USED" << endl;
}

template<typename T, size_t storeSize>
class CallbackStore
{
public:

    CallbackStore() : that_(nullptr) {};
    CallbackStore(T* that) : that_(that) {};

    using CallbackCondition = bool (*) (T*);
    using CallbackAction = void (*) (T*,int);
    struct Step
    {
        CallbackCondition pCallbackCondition;
        CallbackAction pCallbackAction;
    };
    void setStep(int stepId,CallbackCondition pCallbackCondition, CallbackAction pCallbackAction)
    {
        if(stepId<storeSize)
        {
            store[stepId].pCallbackCondition = pCallbackCondition; 
            store[stepId].pCallbackAction = pCallbackAction; 
        }
        else
        {
            cout << "pointer error" << endl;
        }
    }
    void callStep(int stepId, int param) 
    {
        if((stepId<storeSize) &&
        (store[stepId].pCallbackCondition != nullptr) &&
        (store[stepId].pCallbackAction != nullptr) &&
        (that_ != nullptr))
        {
            bool isActive =  (*(store[stepId].pCallbackCondition))(that_);
            if(isActive) {(*(store[stepId].pCallbackAction))(that_,param);}
        }
        else
        {
            cout << "pointer error" << endl;
        }

    }
    Step store[storeSize];
    T* that_;
};

template<typename Base, typename... ArgT>
class Interface : public Base // interface
{
public:
    Interface() : Base() {};
    Interface(ArgT... arg) : Base(arg...) {};

public:
    static bool True(Base* baseInstance)
    {
        return true;
    }
    static bool IsNegative(Base* baseInstance)
    {
        return ((static_cast<Base*>(baseInstance))->getValue() < 0);
    }
    static bool IsNull(Base* baseInstance)
    {
        return ((static_cast<Base*>(baseInstance))->getValue() == 0);
    }
    static bool IsPositive(Base* baseInstance)
    {
        return (IsNegative(baseInstance) == false);
    }
    static void PrintValue(Base* baseInstance, int value)
    {
        cout << "print this value : " << value << "." << endl;
    }
};


template<typename Base>
class Interface<Base,void>// interface
{
public:
    Interface() : Interface<Base,void>() {};
};

class MotherA
{
public:
    MotherA(){};
    MotherA(int x): x_(x){};
    int getValue() { return x_; }
    void setValue(int x) { x_ = x; }

protected:
    int x_ = -3; 
};

class ListModel : public MotherA
{
};
class FinalLChild : public Interface<ListModel>, public CallbackStore<ListModel, STORE_SIZE>
{
public:
    FinalLChild(): Interface(), CallbackStore(this)
    {
        setStep(0, &Interface::IsNegative,  &Interface::PrintValue ); 
        setStep(1, &Interface::IsNegative,  &Interface::PrintValue ); 
        setStep(2, &Interface::IsNull,      &Interface::PrintValue ); 
        setStep(3, &Interface::True,        &Interface::PrintValue ); 
    };

};

class ValueModel : public MotherA
{
public:
    ValueModel() : MotherA(), y_(0) {};
    ValueModel(int x,int y) : MotherA(x), y_(y) {};
    void reset(){x_= y_;};
    int y_ = 0;
};

class ValueChild : public Interface<ValueModel,int,int>, public CallbackStore<ValueModel, STORE_SIZE>
{
public:
    ValueChild() : Interface(), CallbackStore(nullptr){};
    ValueChild(int x,int y): Interface(x,y), CallbackStore(this){};
};

class FinalVChild : public ValueChild
{
public:
    FinalVChild():ValueChild(2,0)
    {
        setStep(0, &Interface::IsPositive,  &Interface::PrintValue ); 
        setStep(1, &Interface::IsPositive,  &Interface::PrintValue ); 
        setStep(2, &Interface::IsNull,      &Interface::PrintValue ); 
        setStep(3, &Interface::IsNull,      &Interface::PrintValue ); 
    };
};


int main()
{
    FinalVChild c;
    for(int i = 0; i < STORE_SIZE; i++)
    {
        c.callStep(i,8);
    }
    cout << "reset:\n";
    c.reset();
    for(int i = 0; i < STORE_SIZE; i++)
    {
        c.callStep(i,8);
    }
    // shall print "print this value : 8." 3 times if x_ is null, twice if x_ is negative.
}

通过添加新的子类,

class ListModel : public MotherA
{
};

class FinalLChild : public Interface<ListModel>, public CallbackStore<ListModel, STORE_SIZE>
{
public:
    FinalLChild(): Interface(), CallbackStore(this)
    {
        setStep(0, &Interface::IsNegative,  &Interface::PrintValue ); 
        setStep(1, &Interface::IsNegative,  &Interface::PrintValue ); 
        setStep(2, &Interface::IsNull,      &Interface::PrintValue ); 
        setStep(3, &Interface::True,        &Interface::PrintValue ); 
    };

};

和main()

    FinalLChild d;
    cout << "d:\n";
        for(int i = 0; i < STORE_SIZE; i++)
    {
        d.callStep(i,8);
    }

这将引发以下编译错误:

main.cpp: In instantiation of ‘class Interface<ListModel>’:
<span class="error_line" onclick="ide.gotoLine('main.cpp',113)">main.cpp:113:57</span>:   required from here
main.cpp:65:5: error: ‘Interface::Interface(ArgT ...) [with Base = ListModel; ArgT = {}]’ cannot be overloaded
     Interface(ArgT... arg) : Base(arg...) {};
     ^~~~~~~~~
main.cpp:64:5: error: with ‘Interface::Interface() [with Base = ListModel; ArgT = {}]’
     Interface() : Base() {};
     ^~~~~~~~~

2 个答案:

答案 0 :(得分:1)

我想问题是这两个构造函数

Interface() : Base() {};
Interface(ArgT... arg) : Base(arg...) {};

ArgT...为空列表时,它们是相同的构造函数并且发生冲突。

我建议SFINAE启用/禁用第二个功能,如下所示

template <bool B = (sizeof...(ArgT)>0u), std::enable_if_t<B, bool> = true>
Interface(ArgT... arg) : Base(arg...) {};

这样,仅当ArgsT...不为空时才启用第二个构造。

一种替代方法是避免SFINAE(有史以来启用的第二个构造函数),但将其转换为一个模板,并带有未使用的模板参数的可变参数未命名列表,因此第一个具有优先级

Interface() : Base() {};

template <typename ...>
Interface(ArgT... arg) : Base(arg...) {};

答案 1 :(得分:0)

代替专用模板

template<typename Base>
class Interface<Base,void>// interface
{
public:
    Interface() : Interface<Base,void>() {};
};

class ListModel : public MotherA
{
};
class FinalLChild : public Interface<ListModel>, public CallbackStore<ListModel, STORE_SIZE>
{
public:
    FinalLChild(): Interface(), CallbackStore(this)
    {
        setStep(0, &Interface::IsNegative,  &Interface::PrintValue ); 
        setStep(1, &Interface::IsNegative,  &Interface::PrintValue ); 
        setStep(2, &Interface::IsNull,      &Interface::PrintValue ); 
        setStep(3, &Interface::True,        &Interface::PrintValue ); 
    };

};

使用class NoneT {};

class NoneT {};

class ListModel : public MotherA
{
};
class FinalLChild : public Interface<ListModel,NoneT>, public CallbackStore<ListModel, STORE_SIZE>
{
public:
    FinalLChild(): Interface(), CallbackStore(this)
    {
        setStep(0, &Interface::IsNegative,  &Interface::PrintValue ); 
        setStep(1, &Interface::IsNegative,  &Interface::PrintValue ); 
        setStep(2, &Interface::IsNull,      &Interface::PrintValue ); 
        setStep(3, &Interface::True,        &Interface::PrintValue ); 
    };

};