4

次の例を検討してください。

#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::declvalT

// ...

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

// ...

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

現在、特定のケースで型を左辺値参照型に変換する(*)ための行は機能しません。std::declval

参照修飾子に関係なくT、メンバー function がある場合に型を受け入れる式を定義する方法はありますか?f


私はそれを使用する実際のケースはなく、実際の使用例を作成することはできません.
この質問は好奇心のためであり、それ以上のものではありません。ref-qualifier
がある 場合には理由があることを理解しており、クラスの設計を壊そうとするべきではありません。

4

2 に答える 2

2

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&&>>>;
}
于 2016-11-06T23:09:59.837 に答える
0

Boost.Hana を使用overload_linearlyして、両方のバリアントをテストできます。

template<typename T>
using lval_of = add_lvalue_reference_t<decay_t<T>>;

auto call_f = hana::overload_linearly(
    [](auto&& t) -> decltype(move(t).f()){},
    [](auto&& t) -> decltype(declval<lval_of<decltype(t)>>().f()){}
);

template<typename T>
auto f() -> decltype(call_f(declval<T>()))
{}

デモ

于 2016-11-06T22:44:08.847 に答える