似たような質問/回答がいくつかありますが、それらの回答をまとめて目的を達成することはできませんでした。特性が欲しい
template<typename Func, typename ReturnType, typename... Args>
struct returns_a { static const bool value; };
そのような
returns_a<F,T,Args>::value
F(Args)
が整形式で、 を返す場合は true ですT
。さらに調査した結果、次のように動作するようになりました。
// value is true if Func(Args...) is well formed
template<typename Func, typename... Args>
class is_callable
{
template <typename F>
static decltype(std::declval<F>()(std::declval<Args>()...), void(), 0) test(int);
template <typename>
static void test(...);
public:
static const bool value = !std::is_void<decltype(test<Func>(0))>::value;
};
// return_type<FunctionSignature>::type is the return type of the Function
template<typename>
struct return_type {};
template<typename ReturnType, typename... Args>
struct return_type<ReturnType(Args...)>
{ typedef ReturnType type; };
// helper class, required to use SFINAE together with variadic templates parameter
// generic case: Func(Args...) is not well-defined
template <typename Func, typename ReturnType, typename dummy, typename... Args>
struct returns_a_helper { static const bool value = false; };
// Func is a function signature
template <typename Func, typename ReturnType, typename... Args>
struct returns_a_helper<Func, ReturnType, typename
std::enable_if<std::is_function<Func>::value>::type, Args...>
{
static const bool value =
std::is_convertible<typename return_type<Func>::type,
ReturnType>::value;
};
// Func(Args...) not a function call, but well-defined
template <typename Func, typename ReturnType, typename... Args>
struct returns_a_helper<Func,ReturnType,typename
std::enable_if<is_callable<Func>::value &&
!std::is_function<Func>::value
>::type, Args...>
{
static const bool value =
std::is_convertible<typename std::result_of<Func(Args...)>::type,
ReturnType>::value;
};
template <typename Func, typename ReturnType, typename... Args>
struct returns_a : returns_a_helper<Func, ReturnType, void, Args...> {};
これは、ファンクターと関数に対して正常に機能するようになりました。簡単なテストを次に示します。
struct base { virtual bool member(int) const = 0; };
struct foo : base { bool member(int x) const { return x&2; } };
struct bar { foo operator()() { return foo(); } };
foo free_function() { return foo(); }
template<typename T, typename Func>
void test(Func const&func)
{
std::cout << std::boolalpha << returns_a<Func,T>::value << std::endl;
}
int main()
{
foo x;
bar m;
test<const base&>([&]() { return x; });
test<const base&>(m);
test<const base&>(free_function);
return 0;
}
まあ、これはうまくいきますが、少し面倒です。より優れた/よりエレガントな/より短いソリューションを持っている人はいますか?