I want to implement a little trait-class to determine if a type has overloaded operator()
properly, so that I can query a type like so:
FunctorCheck<F, void(int, char)>::value
Originally, I got an idea on how to implement this from this question, but after seeing a Cppcon lecture on TMP, it dawned on me that this problem could be solved much more elegantly. This is what I came up with, and this compiles and runs flawlessly on Clang 3.5.0:
template <typename ...>
using void_t = void;
template <typename Functor, typename ... Args>
using FunctorReturn = decltype(declval<Functor>()(declval<Args>()...));
template <typename Functor, typename Signature, typename = void>
struct FunctorCheck: public std::false_type
{};
template <typename Functor, typename R, typename ... Args>
struct FunctorCheck<Functor, R(Args...),
void_t<FunctorReturn<Functor, Args ...>> // SFINAE can kick in here
> : public std::is_same<R, FunctorReturn<Functor, Args ...>>::type
{};
As you might have noticed, I'm using the proposed C++17 void_t
to exploit SFINAE in the template parameters of the specialization. When FunctorReturn
receives a Functor
-type that is incompatible with the argument-list, void_t<FunctorReturn<Functor, Args ...>>
will be ill-formed, SFINAE will kick in and the non-specialized version will be instantiated. If the former expression is well-formed, std::is_same
compares the return-types to determine if we have a match.
In the lecture mentioned before, Walter Brown mentions that this technique has worked from day 1 on Clang, and has not worked on GCC from day 1, simply because they chose different implementations on something the standard failed to specify. However, given that this version is so much more elegant than what I had before, is there anything I can do to make this compile on GCC (>= 4.9)?
(Also, does anyone have any clue as to how this would behave on recent versions of Visual Studio?)
Aucun commentaire:
Enregistrer un commentaire