使用以下代码:
#include <experimental/type_traits>
#include <iostream>
class A {};
class NoMember {};
class HasMember {
public:
void doSomething(A &a) {
std::cout << "Did something!\n";
}
};
template<typename T, typename Arg>
using HasDoSomething = decltype(std::declval<T>().doSomething(std::declval<Arg>()));
template<typename T, typename Arg>
using CanDoSomething = std::experimental::is_detected<HasDoSomething, T, Arg>;
template<typename T, typename Arg, std::enable_if_t<CanDoSomething<T, Arg>::value> * = nullptr>
void TrySomething(T &t, Arg &arg) {
t.doSomething(arg);
}
template<typename T, typename Arg, std::enable_if_t<!CanDoSomething<T, Arg>::value> * = nullptr>
void TrySomething(T &t, Arg &arg) {
std::cout << "Did not do something\n";
}
int main(void) {
A AnA;
NoMember NoMem;
HasMember Mem;
TrySomething(NoMem, AnA);
TrySomething(Mem, AnA);
return 0;
}
我希望它输出:
Did not do something
Did something!
但是,对于g ++ 8.2.0,它会输出:
Did not do something
Did not do something
我猜问题出在这里:
template<typename T, typename Arg>
using HasDoSomething = decltype(std::declval<T().doSomething(std::declval<Arg>()));
由于HasMember::doSomething
引用A,因此它无法绑定到declval<Arg>
“临时”。是正确的,还是我想念其他东西?
如果正确,在引用参数存在的情况下如何使用is_detected
?
答案 0 :(得分:3)
由于
HasMember::doSomething
引用了A
,因此它无法绑定到declval<Arg>
“临时”。是正确的,还是我想念其他东西?
是的。 declval<U>()
返回U&&
。当U=NonMem
时,这意味着一个右值引用被传递到HasMember<T>::doSomething
中,而后者无法绑定到其参数中的左值引用。将模板参数从declval<Arg>()
更改为declval<Arg&>()
将使函数返回左值(请参见reference collapsing)。
答案 1 :(得分:1)
template<typename T, typename Arg, std::enable_if_t<CanDoSomething<T, Arg>::value> * = nullptr>
void TrySomething(T &t, Arg &arg) {
t.doSomething(arg);
}
这问“我可以(T &&)。doSomething(Arg &&), where both
T and
Arg`是右值。
template<typename T, typename Arg, std::enable_if_t<CanDoSomething<T&, Arg&>::value> * = nullptr>
void TrySomething(T &t, Arg &arg) {
t.doSomething(arg);
}
这是你想问的。