使用参考参数检测到std :: experimental :: is_

时间:2018-12-21 01:20:15

标签: c++ template-meta-programming

使用以下代码:

#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

2 个答案:

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

这是你想问的。