- 以下のコードは、メンバ関数const性を正しく
- を扱う機能のとらわれない型を返す
- はそれもあり得る故障
に関する包括的なエラーを出力より短いC++ 14では、実装された関数の戻り値の型を指定する必要はありません。テンプレート化された変数宣言。 rvalueの過負荷を正しく処理するには、別のオーバーロードをas_memfun
に提供する必要があります。
メンバ関数のテストだけでは不十分である場合は、最後のセクションでは、はるかに優れたカスタマイズオプションが用意されていますが、セットアップにも時間がかかります。
#include <utility>
#include <functional>
namespace detail {
template<typename T> struct _false : std::integral_constant<bool, false> { };
template<typename T> struct HasNone {
static_assert(_false<T>::value, "No valid method found");
};
template<typename T, typename R>
constexpr auto as_memfun (R (T::* arg)())
-> R (T::*)()
{ return arg; }
template<typename T, typename R>
constexpr auto as_memfun (R (T::* arg)() const)
-> R (T::*)() const
{ return arg; }
template<typename T> constexpr auto check_has_two(int)
-> decltype(as_memfun(&T::two))
{ return as_memfun(&T::two); }
template<typename T> constexpr auto check_has_two(...)
-> HasNone<T>;
template<typename T> constexpr auto check_has_one(int)
-> decltype(as_memfun(&T::one))
{ return as_memfun(&T::one); }
template<typename T> constexpr auto check_has_one(...)
-> decltype(check_has_two<T>(0))
{ return check_has_two<T>(0); }
template<typename T>
struct res { constexpr static auto detail = check_has_one<T>(0); };
}
template<typename T>
auto func(T t) -> decltype((t.*detail::res<T>::detail)()) {
return (t.*detail::res<T>::detail)();
}
そして、ここでは、あなただけのメンバ関数の存在をテストするよりも、心の中でより広範な構造を持っているように見えるので、おそらくここで、
struct One {
void one();
};
struct Two {
void two();
};
struct TestBoth {
char one() const;
void two();
};
struct TestWilderStuff {
int one;
void two() const;
};
int main() {
func(One{});
func(Two{});
func(TestBoth{});
static_assert(decltype(func(TestBoth{})){} == 0, "Failed function selection");
func(TestWilderStuff{});
}
がしたいいくつかのテストですはるかに強力なメカニズムの始まりです。上記のソリューションの代わりにドロップインを使用することができますが、それははるかに長いですが、より多くのカスタマイズと、あらゆる段階であなたのタイプについて精巧なテストを行う可能性を提供します。
#include <utility>
#include <functional>
namespace detail {
template<typename T> struct _false :
std::integral_constant<bool, false> { };
template<typename T> struct HasNone {
static_assert(_false<T>::value, "No valid method found");
};
// Generic meta templates used below
namespace Generics {
template<typename Getter, typename Else>
struct ChainGetter {
template<typename T> constexpr static auto get_(int)
-> decltype(Getter::template get<T>())
{ return Getter::template get<T>(); }
template<typename T> constexpr static auto get_(...)
-> decltype(Else::template get<T>())
{ return Else::template get<T>(); }
template<typename T> constexpr static auto get()
-> decltype(get_<T>(0))
{ return get_<T>(0); }
};
template<typename Getter, typename Test>
struct TestGetter {
template<typename T, typename R> using _type = R;
template<typename T> constexpr static auto get_()
-> decltype(Getter::template get<T>())
{ return Getter::template get<T>(); }
template<typename T> constexpr static auto test()
-> decltype(Test::template test<T>(get_<T>()));
template<typename T> constexpr static auto get()
-> _type<decltype(test<T>()),
decltype(get_<T>())
>
{ return get_<T>(); }
};
template<template<typename> class F>
struct FailGetter {
template<typename T>
constexpr static auto get() -> F<T>;
};
}
// Test only exists for member function pointer arguments
struct IsMemberFunctionTest {
template<typename _, typename T, typename R>
constexpr static void test (R (T::* arg)());
template<typename _, typename T, typename R>
constexpr static void test (R (T::* arg)() const);
};
// Get member pointer to T::one
struct GetOne {
template<typename T>
constexpr static auto get() -> decltype(&T::one) { return &T::one; }
};
// Get member pointer to T::two
struct GetTwo {
template<typename T>
constexpr static auto get() -> decltype(&T::two) { return &T::two; }
};
using namespace Generics;
using getter_fail = FailGetter<HasNone>;
using get_two_tested = TestGetter<GetTwo, IsMemberFunctionTest>;
using getter_two = ChainGetter<get_two_tested, getter_fail>;
using get_one_tested = TestGetter<GetOne, IsMemberFunctionTest>;
using getter_one = ChainGetter<get_one_tested, getter_two>;
template<typename T>
struct result { constexpr static auto value = getter_one::template get<T>(); };
}
template<typename T>
auto func(T t) -> decltype((t.*detail::result<T>::value)()) {
return (t.*detail::result<T>::value)();
}
のhttps://stackoverflow.com/questions/257288/is-it-possible-to-write-a-template-to-check-for-a-functions-existence – Rene
可能な重複の可能性のある重複[関数の存在をチェックするテンプレートを書くことは可能ですか?](https://stackoverflow.com/questions/257288/is-it-possible-to-write-a-template-to-check-for-a -functions-existence) –
@rene正確には重複していません。もし彼が機能の存在を確認する方法を知っていれば、ここでチェッカーの使い方を知ることはできません。明らかに、彼はその種のチェッカーの使い方を知らない。そうでなければ、彼は再定義について尋ねないだろう。 –