Ihre Nutzung von Zeigern auf Elementfunktion ist eine schlechte Idee; Wenn foo
überlastet ist, scheitert es fälschlicherweise (Sie haben ein foo, aber nicht nur eins). Wer will wirklich "hast du genau ein Foo"? Fast niemand.
Hier ist eine kürzere Version:
template<class T>
using dot_foo_r = decltype(std::declval<T>().foo());
template<class T>
using can_foo = can_apply<dot_foo_r, T>;
wo
namespace details {
template<template<class...>class, class, class...>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z, void, Ts...>;
Nun dot_foo_r
ein bisschen ärgerlich ist das Schreiben.
Mit constexpr
lambdas können wir es weniger lästig machen und es inline machen.
#define RETURNS(...) \
noexcept(noexcept(__VA_ARGS__)) \
-> decltype(__VA_ARGS__) \
{ return __VA_ARGS__; }
Es braucht die RETURNS
Makro, zumindest bis @ Barrys Unterwerfung unter [](auto&&f)RETURNS(f())
zu [](auto&&f)=>f()
gleichwertig sein.
Wir haben dann can_invoke_f
schreiben, die eine ist constexpr
Variante std::is_invokable
:
template<class F>
constexpr auto can_invoke(F&& f) {
return [](auto&&...args)->std::is_invokable<F(decltype(args)...)>{
return {};
};
}
Das gibt uns:
if constexpr(
can_invoke([](auto&&var) RETURNS(var.foo()))(var)
) {
var.foo();
}
oder mit @ Barry vorgeschlagene C++ 20-Syntax:
if constexpr(can_invoke(var=>var.foo())(var)) {
var.foo();
}
und wir sind fertig.
Der Trick ist, dass RETURNS
Makro (oder =>
C++ 20 Feature) lässt uns SFINAE auf einen Ausdruck tun. Das Lambda wird ein einfacher Weg, um diesen Ausdruck als Wert herumzutragen.
Sie könnten
[](auto&&var) ->decltype(var.foo()) { return var.foo(); }
schreiben, aber ich denke, RETURNS
es wert ist (und Ich mag Makros nicht).
[Maßgebliche] (https://meta.stackoverflow.com/a/323382/2069064). Eine Antwort könnte sein, dass es hier keine Substitution gibt, also wie kann es SFINAE geben? Eine andere Antwort könnte darin bestehen, dass sie nicht berücksichtigt wurde, da es sich bei den Vorschlägen immer um das 'if' handelte, das einen' Bool' nahm? – Barry
@Barry Hoffnungsvoll bearbeitete Frage in eine Form, die eine klare Antwort haben kann. War ursprünglich über etwas nach dem Motto [diese Art von Antwort] (https://stackoverflow.com/a/6623089/4832499) –