Can't restrict overload of template function `operator+` to my class hierarchy using `enable_if` and `is_base_of`

扶醉桌前 提交于 2020-01-15 06:00:08

问题


I'm creating an operator+ using a template function for a type hierarchy. First simple attempt worked fine until I tried to concatenate a string in another part of the code and GCC 8.3 tried to use my operator+.

Trying to use enable_if and is_base_of to restrict my version to my types so SFINAE handles the issue.

One attempt among many is:

template <  //
    typename T1, //
    typename T2, typename std::enable_if_t<std::is_base_of_v<LogicGateAbs, T2>, T2>       //
>
inline OrGate operator +(T1&& lhs, T2&& rhs) {
    return OrGate { LogicGateAbs::make_concrete(lhs), LogicGateAbs::make_concrete(rhs) };
}

Here the compiler gives the types correctly:

./src2/test.cpp:90:11: error: no match for ‘operator+’ (operand types are ‘TrueGate’ and ‘TrueGate’)
     (True + True);
      ~~~~~^~~~~~

But why does it then return 'false' for is_base_of since LogicGateAbs is the base of TrueGate?

../src2/test.cpp:83:15: note: candidate: ‘template<class T1, class T2, typename std::enable_if<is_base_of_v<LogicGateAbs, T2>, T2>::type <anonymous> > OrGate operator+(T1&&, T2&&)’
 inline OrGate operator +(T1&& lhs, T2&& rhs) {
               ^~~~~~~~
../src2/test.cpp:83:15: note:   template argument deduction/substitution failed:
../src2/test.cpp:81:32: error: no type named ‘type’ in ‘struct std::enable_if<false, TrueGate&>’
     typename T2, typename std::enable_if_t<std::is_base_of_v<LogicGateAbs, T2>, T2>       //
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Gone through every version of this on StackOverflow without getting a version to work.

The base function works as needed. The rvalue reference is necessary for the inputs are often temporary values.


回答1:


Notice the TrueGate& in the error message: that’s T2, deduced as such because the argument is an lvalue. std:is_base_of requires actual class types, so use std::remove_reference_t.




回答2:


You need ::std::remove_reference, yes. But you also need to check the types of both arguments. :-/

template <typename T1, typename T2>
inline typename
::std::enable_if<
    ::std::is_base_of_v<LogicGateAbs, typename std::remove_reference_t<T1>> &&
    ::std::is_base_of_v<LogicGateAbs, typename std::remove_reference_t<T2>>,
    AndGate>::type
operator *(T1 &&lhs, T2 &&rhs) {
    using NRT1 = typename ::std::remove_reference<T1>::type;
    using NRT2 = typename ::std::remove_reference<T2>::type;
    AndGate gate { ::std::make_unique<NRT1>(::std::move(lhs)), ::std::make_unique<NRT2>(::std::move(rhs)) };
    return gate;
}

Now it won't match if either side of the expression isn't derived from LogicGateAbs. I actually have a really bad feeling about the non-template version. These only work if the arguments are temporaries. The only reason it's working for TrueGate is that the move constructor for it is equivalent to its copy constructor. The move constructors for the things with unique_ptr members are destructive moves.




回答3:


The final version required std::remove_reference_t and the = supplied by @Davis and `@Sam. Kudos to both.

In LogicalGateAbs:

class LogicalGateAbs {
...
    template <typename T>
    static inline auto make_concrete(T&& rhs) {
        using NRT = typename std::remove_reference<T>::type;
        return std::make_unique < NRT > (std::move(rhs));
    }
};

And the version of operator+:

//----------------------------------------------------------------------
template <typename T>
using check_type = std::enable_if_t<std::is_base_of_v<LogicGateAbs, typename std::remove_reference_t<T>>, T>;
//-----------------------------------------------------------------------
template <typename T1, typename = check_type<T1>, typename T2, typename = check_type<T2> >
inline OrGate operator +(T1&& lhs, T2&& rhs) {
    return OrGate { "op+", LogicGateAbs::make_concrete(lhs), LogicGateAbs::make_concrete(rhs) };
}


来源:https://stackoverflow.com/questions/56502143/cant-restrict-overload-of-template-function-operator-to-my-class-hierarchy-u

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!