无法使用"enable_if"和"is_base_of"将模板函数"operator+"的重载限制到我的类层次结构

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

本文关键字:重载 operator+ 函数 我的 层次结构 enable if of base is      更新时间:2023-10-16

>我正在使用类型层次结构的模板函数创建一个operator+。第一次简单的尝试工作正常,直到我尝试在代码的另一部分连接一个字符串,GCC 8.3 尝试使用我的operator+

尝试使用 enable_ifis_base_of 将我的版本限制为我的类型,以便 SFINAE 处理问题。

众多尝试中的一个是:

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) };
}

在这里,编译器正确地给出了类型:

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

但是为什么它会为is_base_of返回"false",因为LogicGateAbsTrueGate的基础?

../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>       //
                                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在StackOverflow上浏览了每个版本,但没有获得一个版本。

基本函数根据需要工作。右值引用是必需的,因为输入通常是临时值。

请注意错误消息中的TrueGate&:这是T2,因为参数是左值。 std:is_base_of需要实际的类类型,因此请使用std::remove_reference_t

你需要::std::remove_reference,是的。但是您还需要检查这两个参数的类型。:-/

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;
}

现在,如果表达式的任何一侧不是从 LogicGateAbs 派生的,它将不匹配。我实际上对非模板版本有一种非常糟糕的感觉。这些仅在参数是临时参数时才有效。它适用于TrueGate的唯一原因是它的移动构造函数等效于其复制构造函数。具有unique_ptr成员的事物的移动构造函数是破坏性移动。

最终版本需要std::remove_reference_t=由 @Davis 和 '@Sam 提供。向两者致敬。

在 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));
    }
};

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) };
}