Enable_if用于模板功能专业化

时间:2018-01-04 14:57:00

标签: c++

我在C ++中玩装饰模式。在像书中那样工作之后,我决定创建一个模板函数(称为“装饰”)来帮助我根据装饰器类,具体类和接口类构造装饰对象。

基本模板功能完美无缺。但后来我决定我也想要一个空的decorator实现,除了调用具体的对象方法之外别无其他。这很有效,我可以坚持这个设计,但是当我使用空的装饰器时,我仍然会有一个虚拟调用,实际上除了调用另一个虚拟方法之外什么也没做。我想避免这种不必要的间接,我决定专门化我的模板函数,以便在使用空装饰器时,它返回未修饰的对象(具体对象)。 我想使用enable_if专门化我的模板函数,但不知何故它不想编译。我一定做错了什么。请帮我。我的代码有什么问题?

#include <iostream>
#include <memory>
#include <type_traits>
using namespace std;

struct IA {
    virtual ~IA() {}
    virtual void doSth() = 0;
};

struct ConcreteA : public IA
{
    void doSth() override 
    {
         cout << "concrete: doSth" << endl;
    }
};

struct LoggingDecoratorA : public IA {
    LoggingDecoratorA(unique_ptr<IA> pia) : _pia(move(pia)) {}
    void doSth() override 
    {
         cout << "calling doSth" << endl;
        _pia->doSth();
    }
    unique_ptr<IA> _pia;
};

struct EmptyDecoratorA : public IA {
    EmptyDecoratorA(unique_ptr<IA> pia) : _pia(move(pia)) {}
    void doSth() override 
    {
        _pia->doSth();
    }
    unique_ptr<IA> _pia;
};

void fun(IA* pia)
{
    pia->doSth();
}

template<typename Decorator, typename Concrete, typename Interface, typename X = enable_if_t<!is_same<Decorator, EmptyDecoratorA>::value>>
unique_ptr<Interface> decorate()
{
    return make_unique<Decorator>((make_unique<Concrete>()));
}

template<typename Decorator, typename Concrete, typename Interface, typename X = void>
unique_ptr<Interface> decorate()
{
    return make_unique<Concrete>();
}

int main()
{ 
    auto pia = decorate<LoggingDecoratorA, ConcreteA, IA>();
    fun(pia.get());
}

2 个答案:

答案 0 :(得分:1)

试试这个:

template<typename Decorator, typename Concrete, typename Interface>
typename enable_if<is_same<Decorator, EmptyDecoratorA>::value, unique_ptr<Interface>>::type
decorate()
{
    return make_unique<Decorator>((make_unique<Concrete>()));
}

template<typename Decorator, typename Concrete, typename Interface>
typename enable_if<!is_same<Decorator, EmptyDecoratorA>::value, unique_ptr<Interface>>::type
decorate()
{
    return make_unique<Concrete>();
}

答案 1 :(得分:0)

template<typename Decorator, typename Concrete, typename Interface,
    typename X = enable_if_t<!is_same<Decorator, EmptyDecoratorA>::value>>
unique_ptr<Interface> decorate()
{
    return make_unique<Decorator>((make_unique<Concrete>()));
}

template<typename Decorator, typename Concrete, typename Interface,
    typename X = void>
unique_ptr<Interface> decorate()
{
    return make_unique<Concrete>();
}

这不是SFINAE的工作方式(默认模板类型参数不是函数签名的一部分,请查看此question以获取更多详细信息)。

您可以按如下方式更改代码:

template<typename Decorator, typename Concrete, typename Interface>
auto decorate() ->
    enable_if_t<!is_same<Decorator, EmptyDecoratorA>::value, unique_ptr<Interface>>
{
    return make_unique<Decorator>((make_unique<Concrete>()));
}


template<typename Decorator, typename Concrete, typename Interface>
auto decorate() ->
    enable_if_t<is_same<Decorator, EmptyDecoratorA>::value, unique_ptr<Interface>>
{
    return make_unique<Concrete>();
}

并将std::enable_if_t移至返回类型。现在正确应用SFINAE,因为返回类型是函数签名的一部分。