test_sfinae.cpp

Back to SFINAE constraints

test/pastel/sys/

// Description: Testing for SFINAE
// DocumentationOf: sfinae.h

#include "test/test_init.h"

#include <pastel/sys/sfinae.h>

namespace
{

    // SFINAE in the default template parameter value.
    //
    // Disadvantages:
    // * extraneous  = 0. 

    template <
        integer N,
        RequiresC<N == 1> = 0>
    std::true_type f();

    template <
        integer N,
        RequiresC<N != 1> = 0>
    std::false_type f();

}

TEST_CASE("DefaultTemplateParameterValue (sfinae)")
{
    PASTEL_STATIC_ASSERT(!decltype(f<0>())::value);
    PASTEL_STATIC_ASSERT(decltype(f<1>())::value);
}

namespace
{

    // SFINAE in the default template parameter type.

    template <
        integer N,
        typename = RequiresC<N == 1>>
    std::true_type g();

    template <
        integer N,
        typename = RequiresC<N != 1>>
    std::false_type g();

}

TEST_CASE("DefaultTemplateParameterType (sfinae)")
{
    PASTEL_STATIC_ASSERT(!decltype(g<0>())::value);
    PASTEL_STATIC_ASSERT(decltype(g<1>())::value);
}

namespace
{

    // SFINAE in the return type.
    //
    // Disadvantages:
    // * garbles the return type.

    template <integer N>
    EnableIfC<N == 1, std::true_type> h();

    template <integer N>
    EnableIfC<N != 1, std::false_type> h();

}

TEST_CASE("ReturnType (sfinae)")
{
    // Visual Studio 2013: pass
    // Visual Studio 2013 Compiler Nov 2013 CTP: fail
    // Visual Studio 14 CTP4: pass
    PASTEL_STATIC_ASSERT(!decltype(h<0>())::value);
    PASTEL_STATIC_ASSERT(decltype(h<1>())::value);
}

namespace
{

    // SFINAE in the parameter
    //
    // Disadvantages:
    // * garbles the parameter list

    template <integer N>
    std::true_type k(RequiresC<N == 1> = 0);

    template <integer N>
    std::false_type k(RequiresC<N != 1> = 0);

}

TEST_CASE("Parameter (sfinae)")
{
    PASTEL_STATIC_ASSERT(!decltype(k<0>())::value);
    PASTEL_STATIC_ASSERT(decltype(k<1>())::value);
}

namespace
{

    // Complex SFINAE constraint

    template <
        typename Type,
        Requires<
            Or<
                And<
                    std::is_same<float, float>,
                    std::is_same<Type, float>,
                    std::is_same<float, Type>,
                    std::is_same<Type, Type>,
                    std::is_fundamental<Type>
                >,
                And<
                    std::is_same<int, int>,
                    std::is_same<Type, int>,
                    std::is_same<int, Type>,
                    std::is_same<Type, Type>,
                    std::is_integral<Type>
                >
            >,
            std::is_same<Type, Type>
        > = 0
    >
    std::true_type m(Type);

    std::false_type m(...);
}

TEST_CASE("Complex (sfinae)")
{
    PASTEL_STATIC_ASSERT(decltype(m(1.0f))::value);
    PASTEL_STATIC_ASSERT(decltype(m(1))::value);
    PASTEL_STATIC_ASSERT(!decltype(m('a'))::value);
}

namespace
{

    class A
    {
    public:
        // SFINAE in the default template parameter value.

        template <
            integer N,
            RequiresC<N == 1> = 0>
        std::true_type f();

        template <
            integer N,
            RequiresC<N != 1> = 0>
        std::false_type f();

        // SFINAE in the default template parameter type.

        template <
            integer N,
            typename = RequiresC<N == 1>>
        std::true_type g();

        template <
            integer N,
            typename = RequiresC<N != 1 >>
        std::false_type g();

        // SFINAE in the return type.

        template <integer N>
        EnableIfC<N == 1, std::true_type> h();

        template <integer N>
        EnableIfC<N != 1, std::false_type> h();

        // SFINAE in the parameter

        template <integer N>
        std::true_type k(RequiresC<N == 1> = 0);

        template <integer N>
        std::false_type k(RequiresC<N != 1> = 0);
    };

}

TEST_CASE("Class (sfinae)")
{
    A a;

    static_assert(std::is_same<decltype(a.f<0>()), std::false_type>::value, "fail");
    static_assert(std::is_same<decltype(a.f<1>()), std::true_type>::value, "fail");

    static_assert(std::is_same<decltype(a.g<0>()), std::false_type>::value, "fail");
    static_assert(std::is_same<decltype(a.g<1>()), std::true_type>::value, "fail");

    // Visual Studio 2013: pass
    // Visual Studio 2013 Compiler Nov 2013 CTP: fail
    // Visual Studio 14 CTP4: pass
    static_assert(std::is_same<decltype(a.h<0>()), std::false_type>::value, "fail");
    static_assert(std::is_same<decltype(a.h<1>()), std::true_type>::value, "fail");

    PASTEL_STATIC_ASSERT((std::is_same<decltype(a.k<0>()), std::false_type>::value));
    PASTEL_STATIC_ASSERT((std::is_same<decltype(a.k<1>()), std::true_type>::value));

    a;
}