std :: экспериментальный :: is_detected со ссылочным аргументом - PullRequest
0 голосов
/ 21 декабря 2018

Со следующим кодом:

#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 голосов
/ 21 декабря 2018
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` - это rvalues.

template<typename T, typename Arg, std::enable_if_t<CanDoSomething<T&, Arg&>::value> * = nullptr>
void TrySomething(T &t, Arg &arg) {
  t.doSomething(arg);
}

это то, что вы хотите спросить.

0 голосов
/ 21 декабря 2018

Поскольку HasMember::doSomething принимает A по ссылке, он не может связываться с declval<Arg> «временным».Это правильно, или я что-то упускаю?

Это верно.declval<U>() возвращает U&&.Когда U=NonMem это означает, что ссылка на rvalue передается в HasMember<T>::doSomething, которая не может привязаться к ссылке на lvalue в своем параметре.Изменение аргумента шаблона с declval<Arg>() на declval<Arg&>() приведет к тому, что функция будет возвращать lvalue (см. свертывание ссылки ).

...