Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization enable_if

I am trying to specialize a template this way:

class PropertyBase
{
public:
    SfPropertyBase(string name)
    {
        Name = name;
    }

    virtual ~SfPropertyBase() {}

    string Name;

    virtual bool FromString(Object* obj, string str) = 0;

};


template< typename T>
class Property : public SfPropertyBase
{
public:
    Property(string name) : SfPropertyBase(name)
    {
        //specific to Property stuff
    }



    template<typename U = T>
    typename std::enable_if<(std::is_class<U>::value && std::is_pointer<U>::value), bool>::type
    FromString(Object* obj, string str)
    {
        //do something
        return true;
    }

    template<typename U = T>
    typename std::enable_if<!std::is_class<U>::value || !std::is_pointer<U>::value), bool>::type
    FromString(Object* obj, string str)
    {
        //do something
        return true;
    }
}

Then, when I try to initialize an instance of this class:

 auto prop = new Property<int>("IntProperty");

I get invalid new-expression of abstract class type Property<int>. I understand that there is an abstract function in PropertyBase, but I also provide both specializations for Property, where T is a class and where it isn't.

What is going on and how to fix it?

Note: what I want to achieve is to specialize FromString if T is a class/pointer and all the other cases.

like image 998
Sturm Avatar asked May 21 '19 06:05

Sturm


2 Answers

Both the FromString in Property are function template, they can't override the non-template virtual function of the base class. (In fact functions templates cannot be virtual functions).

You could add another non-template FromString in Property; and you can ensure the overriding by using the keyword orverride. e.g.

bool FromString(Object* obj, string str) override {
    return FromString<>(obj, str);
}

LIVE

like image 171
songyuanyao Avatar answered Sep 30 '22 12:09

songyuanyao


A function template cannot be used as an overrider for a non-template virtual function. A function template is not a function, it's a recipe for creating functions on demand when a call is made.

Code will have to call FromString on your derived class object directly for SFINAE to work. If you want to provide a different overrider based on the template parameter type, one approach is to go via an intermediate base.

template<typename T, typename = void>
struct FromStringProvider;

template<typename T>
struct FromStringProvider<T, typename std::enable_if<(std::is_class<U>::value && std::is_pointer<U>::value)>::type> : SfPropertyBase {
    bool FromString(Object* obj, string str) override
    {
        //do something
        return true;
    }
};

If you need access to the deriving class, then a CRTP based approach can be used. Just pass the deriving class as an extra parameter and rely on its static interface to access the parts you need.

This alternative approach is especially useful if you have sets of virtual functions, all under the same conditions.

like image 41
StoryTeller - Unslander Monica Avatar answered Sep 30 '22 14:09

StoryTeller - Unslander Monica