我正在使用模板函数为类型层次结构创建operator+
。第一次简单的尝试就可以正常工作,直到我尝试在代码的另一部分中连接字符串,并且GCC 8.3尝试使用我的operator+
。
尝试使用enable_if
和is_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
是LogicGateAbs
的基数而又为TrueGate
返回'false'?
../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上浏览了此版本的每个版本,而没有一个版本可以正常工作。
基本功能根据需要工作。右值引用是必需的,因为输入通常是临时值。
答案 0 :(得分:1)
请注意错误消息中的TrueGate&
:T2
,其推论是因为该参数是一个左值。 std:is_base_of
需要实际的类类型,因此请使用std::remove_reference_t
。
答案 1 :(得分:1)
您需要::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
派生的,它将不匹配。对于非模板版本,我实际上有一种非常不好的感觉。如果参数是临时变量,则这些 only 起作用。它适用于TrueGate
的唯一原因是它的move构造函数等同于其copy构造函数。具有unique_ptr
成员的事物的move构造函数是破坏性的动作。
答案 2 :(得分:0)
最终版本需要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) };
}