LoginSignup
18
9

More than 5 years have passed since last update.

メタ関数コールバックを使おう

Last updated at Posted at 2017-10-31

初めに

SFINAEを使ってメタ関数を書く際、いろいろな方法がありますがメタ関数コールバックという技法を使った書き方を推したいのでまとめます

これまでの書き方

例として任意の型がfunc()をもつかどうかチェックするメタ関数

初期の書き方

関数のオーバーロードと優先順位を利用した方法

SFINAE1
template<class T>
struct HasFunc
{
private:
    template<class U>
    static auto check()->decltype(std::declval<U>().func(), std::true_type{});
    template<class>
    static std::false_type check(...);
public:

    static constexpr bool value = decltype(check<T>())::value;

};

void_tを使った書き方

任意の型が型引数にあるときvoidを返すvoid_tを使い、template特殊化する方法

template<class...>
using void_t = void;
SFINAE2
template<class T,class = void>
struct HasFunc:std::false_type
{};
template<class T>
struct HasFunc < T, std::void_t<decltype(std::declval<T>().func())> > :std::true_type
{};

メタ関数コールバックを使ったこれからの書き方

テンプレートテンプレート引数を利用し、std::void_tの方法をさらにジェネリックにした方法

namespace detail
{
    template<class AlwaysVoid, template<class...>class Op, class ...Args>
    struct is_detected_impl :std::false_type
    {};
    template<template<class...>class Op, class ...Args>
    struct is_detected_impl<std::void_t<Op<Args...>>, Op, Args...> :std::true_type
    {};
}
//こいつを使う
template<template<class...>class Op, class ...Args>
using is_detected = detail::is_detected_impl<void, Op, Args...>;

std::is_detectedはまだないので自作すればいい

SFINAE3
template<class T>
using HasFuncOp = decltype(std::declval<T>().func());

template<class T>
using HasFunc = is_detected<HasFuncOp, T>;

これまでの書き方と比べてだいぶすっきりしたと思う
もっと広まってほしい

参考

https://ja.wikipedia.org/wiki/SFINAE
http://en.cppreference.com/w/cpp/experimental/is_detected

18
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
9