// Description: Test whether well-formed code compiles
#ifndef PASTELSYS_COMPILES_H
#define PASTELSYS_COMPILES_H
#include <type_traits>
#include <utility>
namespace Pastel
{
    //! Tests whether well-formed code compiles.
    /*!
   Code:
   A class/alias template whose instantiation 
   Code<TypeSet...> encapsulates the code to 
   be tested.
   TypeSet:
   The arguments of Code.
   */
    template <
        template <typename...> class Code,
        typename... TypeSet
    >
    struct Compiles
    {
    private:
        template <
            typename... T,
            typename = Code<T...>
            >
        static std::true_type test(T&&...);
        static std::false_type test(...);
    public:
        static constexpr bool value =
            decltype(test(std::declval<TypeSet>()...))::value;
    };
    //! Computes a compile-time function, if it compiles.
    /*!
   Otherwise returns a fail-type.
   FailType:
   The type to return in case Code<TypeSet...>
   does not compile.
   Code:
   A class/alias template such that Code<TypeSet..>
   provides the result of the computation, if
   it compiles.
   TypeSet:
   The set of arguments to Code.
   */
    template <
        typename FailType,
        template <typename...> class Code,
        typename... TypeSet
    >
    struct Compute_F
    {
    private:
        template <
            typename... T,
            typename Return = Code<T...>
            >
        static Return test(T&&...);
        static FailType test(...);
    public:
        using type = 
            decltype(test(std::declval<TypeSet>()...));
    };
    template <
        typename FailType,
        template <typename...> class Code,
        typename... TypeSet
    >
    using Compute = 
        typename Compute_F<FailType, Code, TypeSet...>::type;
}
#endif