// Description: Testing for concepts
// DocumentationOf: concept.h
#include "test/test_init.h"
#include <pastel/sys/concept.h>
namespace
{
struct Goo_Concept
{
template <typename Type>
auto requires_(Type&& t) -> decltype(
conceptCheck(
++t,
t * t,
t.f()
));
};
struct FooGoo_Concept
: Refines<Goo_Concept>
{
template <typename Type>
auto requires_(Type&& t) -> decltype(
conceptCheck(
// The return-type of g() is void;
// the comma can be used to assign
// an argument.
(t.g(), 0)
));
};
struct Doo_Concept
{
template <typename Type, typename A_Goo>
auto requires_(Type&& t, A_Goo&& a) -> decltype
(
conceptCheck(
Concept::isModelOf<Goo_Concept>(a),
Concept::hasType<Type&>(t += a)
)
);
};
struct Empty_Concept
{
template <typename Type>
void requires_(Type&& t);
};
struct Baseless_Concept
: Refines<>
{};
class Green_Goo
{
public:
Green_Goo& operator++();
Green_Goo& operator*(const Green_Goo& that);
integer f();
};
class SuperGreen_FooGoo
: public Green_Goo
{
public:
void g();
};
class Green_Doo
{
public:
Green_Doo& operator+=(const Green_Goo& that)
{
return *this;
}
};
class Red_Doo
{
public:
Red_Doo& operator+=(const Green_Goo& that)
{
return *this;
}
};
class Blue_Doo
{
public:
Blue_Doo& operator+=(const SuperGreen_FooGoo& that)
{
return *this;
}
};
class Something_Else
{
public:
void g();
};
}
TEST_CASE("Models (concept)")
{
PASTEL_CONCEPT_CHECK(Green_Goo, Goo_Concept);
PASTEL_CONCEPT_CHECK(Green_Goo, Empty_Concept);
PASTEL_CONCEPT_CHECK(Green_Goo, Baseless_Concept);
PASTEL_CONCEPT_REJECT(Green_Goo, FooGoo_Concept);
PASTEL_CONCEPT_CHECK(Green_Goo&, Goo_Concept);
PASTEL_CONCEPT_CHECK(Green_Goo&&, Goo_Concept);
PASTEL_CONCEPT_CHECK(const Green_Goo, Goo_Concept);
PASTEL_CONCEPT_CHECK(const Green_Goo&, Goo_Concept);
PASTEL_CONCEPT_CHECK(const Green_Goo&&, Goo_Concept);
PASTEL_CONCEPT_CHECK(SuperGreen_FooGoo, Goo_Concept);
PASTEL_CONCEPT_CHECK(SuperGreen_FooGoo, FooGoo_Concept);
PASTEL_CONCEPT_CHECK(SuperGreen_FooGoo, Empty_Concept);
PASTEL_CONCEPT_CHECK(SuperGreen_FooGoo, Baseless_Concept);
PASTEL_CONCEPT_CHECK(SuperGreen_FooGoo&, Goo_Concept);
PASTEL_CONCEPT_CHECK(SuperGreen_FooGoo&&, Goo_Concept);
PASTEL_CONCEPT_CHECK(const SuperGreen_FooGoo, Goo_Concept);
PASTEL_CONCEPT_CHECK(const SuperGreen_FooGoo&, Goo_Concept);
PASTEL_CONCEPT_CHECK(const SuperGreen_FooGoo&&, Goo_Concept);
PASTEL_CONCEPT_CHECK_DIRECT(Something_Else, FooGoo_Concept);
PASTEL_CONCEPT_REJECT_BASE(Something_Else, FooGoo_Concept);
PASTEL_CONCEPT_REJECT(Something_Else, FooGoo_Concept);
PASTEL_CONCEPT_REJECT(Something_Else&, FooGoo_Concept);
PASTEL_CONCEPT_REJECT(Something_Else&&, FooGoo_Concept);
PASTEL_CONCEPT_REJECT(const Something_Else, FooGoo_Concept);
}
TEST_CASE("ParametrizedModels (concept)")
{
PASTEL_CONCEPT_CHECK(Green_Doo, Doo_Concept(Green_Goo));
PASTEL_CONCEPT_CHECK(Red_Doo, Doo_Concept(Green_Goo));
PASTEL_CONCEPT_CHECK(Red_Doo, Doo_Concept(SuperGreen_FooGoo));
PASTEL_CONCEPT_CHECK(Blue_Doo, Doo_Concept(SuperGreen_FooGoo));
PASTEL_CONCEPT_REJECT(Blue_Doo, Doo_Concept(Green_Goo));
PASTEL_CONCEPT_REJECT(Something_Else, Doo_Concept(Green_Goo));
}
namespace
{
template <typename A_Doo>
void f(const A_Doo& a)
{
PASTEL_CONCEPT_CHECK(A_Doo, Doo_Concept(Green_Goo));
}
template <
typename A_Doo,
Requires<Models<A_Doo, Doo_Concept(Green_Goo)>> = 0>
std::true_type g(const A_Doo& a)
{
return std::true_type();
}
template <
typename A_Doo,
DisableIf<Models<A_Doo, Doo_Concept(Green_Goo)>> = 0>
std::false_type g(const A_Doo& a)
{
return std::false_type();
}
}
TEST_CASE("FunctionModels (concept)")
{
f(Green_Doo());
f(Red_Doo());
// This should trigger a nice error.
//f(Blue_Doo());
PASTEL_STATIC_ASSERT(decltype(g(Green_Doo()))::value);
PASTEL_STATIC_ASSERT(decltype(g(Red_Doo()))::value);
PASTEL_STATIC_ASSERT(!decltype(g(Green_Goo()))::value);
PASTEL_STATIC_ASSERT(!decltype(g(Something_Else()))::value);
}
namespace
{
template <typename A_Doo>
class TestClass
{
PASTEL_CONCEPT_CHECK(A_Doo, Doo_Concept(Green_Goo));
};
}
TEST_CASE("ClassModels (concept)")
{
TestClass<Green_Doo> green;
TestClass<Red_Doo> red;
// This should trigger a nice error.
//TestClass<Blue_Doo> blue;
unused(red, green);
}
TEST_CASE("Refines (concept)")
{
PASTEL_STATIC_ASSERT((!IsRefined<Goo_Concept>::value));
PASTEL_STATIC_ASSERT((!IsRefined<Empty_Concept>::value));
PASTEL_STATIC_ASSERT((IsRefined<FooGoo_Concept>::value));
PASTEL_STATIC_ASSERT((!IsRefined<Baseless_Concept>::value));
}
TEST_CASE("BaseConcepts (concept)")
{
PASTEL_STATIC_ASSERT((
std::is_same<
BaseConcepts<Goo_Concept>,
Refines<>
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
BaseConcepts<FooGoo_Concept>,
Refines<Goo_Concept>
>::value));
}
TEST_CASE("FirstModeledConcept (concept)")
{
PASTEL_STATIC_ASSERT((
std::is_same<
FirstModeledConcept<Green_Goo, Goo_Concept, FooGoo_Concept>,
Goo_Concept
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
FirstModeledConcept<Green_Goo, FooGoo_Concept, Goo_Concept>,
Goo_Concept
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
FirstModeledConcept<SuperGreen_FooGoo, Goo_Concept, FooGoo_Concept>,
Goo_Concept
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
FirstModeledConcept<SuperGreen_FooGoo, FooGoo_Concept, Goo_Concept>,
FooGoo_Concept
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
FirstModeledConcept<Green_Goo>,
void
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
FirstModeledConcept<Something_Else, Goo_Concept>,
void
>::value));
}
TEST_CASE("MostRefinedConcept (concept)")
{
PASTEL_STATIC_ASSERT((
std::is_same<
MostRefinedConcept<Green_Goo, FooGoo_Concept>,
Goo_Concept
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
MostRefinedConcept<SuperGreen_FooGoo, FooGoo_Concept>,
FooGoo_Concept
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
MostRefinedConcept<Something_Else, FooGoo_Concept>,
void
>::value));
}
TEST_CASE("CoarsestFailedConcept (concept)")
{
PASTEL_STATIC_ASSERT((
std::is_same<
CoarsestFailedConcept<Green_Goo, FooGoo_Concept>,
Refines<FooGoo_Concept>
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
CoarsestFailedConcept<SuperGreen_FooGoo, FooGoo_Concept>,
Refines<>
>::value));
PASTEL_STATIC_ASSERT((
std::is_same<
CoarsestFailedConcept<Something_Else, FooGoo_Concept>,
Refines<Goo_Concept>
>::value));
}
// In this test we want to make sure that the concept-checking
// does not look into the definition of those functions which are
// called from the concept-check.
namespace
{
struct Some_Concept
{
template <
typename Type
>
auto requires_(Type&& t) -> decltype
(
conceptCheck(
fSome(t)
)
);
};
struct A {};
template <typename Type>
integer fSome(Type a)
{
// We need to make the check dependent on Type,
// or otherwise the compiler checks the static assert
// already on the non-dependent phase.
static constexpr bool False =
!std::is_same<Type, Type>::value;
static_assert(False, "Concept checking looks into the definition, although it should not.");
return 0;
}
}
TEST_CASE("Declaration")
{
PASTEL_CONCEPT_CHECK(A, Some_Concept);
}