c – 尾随返回类型,declval和引用限定符:它们可以一起工作吗?

请考虑以下示例:

#include <utility>

struct A { void f() {} };
struct B { void f() & {} };
struct C { void f() && {} };

template<typename T>
auto f() -> decltype(std::declval<T>().f())
{}

int main() {
    f<A>();
    // f<B>(); // (*)
    f<C>();
}

当用B(行(*))调用时,代码不再编译,因为std :: declval在特定情况下将T转换为右值引用类型.
如果我们稍后稍微改变它,我们就会遇到相反的问题:

// ...

template<typename T>
auto f() -> decltype(std::declval<T&>().f())
{}

// ...

int main() {
    f<A>();
    f<B>();
    // f<C>(); // (*)
}

现在,在(*)处的行不适用于std :: declval在特定情况下将类型转换为左值引用类型.

有没有办法定义一个接受类型T的表达式,如果它有一个成员函数f,无论它的引用限定符是什么?

我没有任何实际案例,我会使用它,我不能做任何真实的使用例子.
这个问题仅仅是为了好奇,仅此而已.
我知道有一个理由,如果ref-qualifier存在,我不应该试图破坏类的设计.

最佳答案 如果表达式declval< T>().f(declval< Args>()…)是有效调用,则构建一个返回true的类型特征.然后通过U&和U&&指示类型为T的左值或右值对象

namespace detail{
  template<class...>struct voider{using type=void;};
  template<class... Ts>using void_t=typename voider<Ts...>::type;

  template<template<class...> class, class=void, class...>
  struct can_apply : false_type { };

  template<template<class...> class L, class... Args>
  struct can_apply<L, void_t<L<Args...>>, Args...> : true_type {};

  template<class T>
  using rvalue = decltype(declval<T>().f());
  template<class T>
  using lvalue = decltype(declval<T&>().f());

  template<class T>
  using can_apply_f
    = integral_constant<bool, detail::can_apply<rvalue, void_t<>, T>{} ||
                              detail::can_apply<lvalue, void_t<>, T>{}>;
}

template<class T>
enable_if_t<detail::can_apply_f<T>{}>
f();

在C 17中,这有点简单:

namespace detail{
  auto apply=[](auto&&g,auto&&...xs)->decltype(decltype(g)(g).f(decltype(xs)(xs)...),void()){};

  template<class T>
  using ApplyF = decltype(apply)(T);

  template<class T>
  using can_apply_f = std::disjunction<std::is_callable<ApplyF<T&>>, std::is_callable<ApplyF<T&&>>>;
}
点赞