Со следующим кодом:
#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
при наличии ссылочных аргументов?