lumiera_/tests/library/meta/generator-test.cpp
Ichthyostega 20392eee1c clean-up: successfully replaced the old fixed type sequence (closes: #987)
This resolves an intricate problem related to metaprogramming with
variadic templates and function signatures. Due to exceptional complexity,
a direct solution was blocked for several years, and required a better
organisation of the support code involved; several workarounds were
developed, gradually leading to a transition path, which could now
be completed in an focused clean-up effort over the last week.

Metaprogramming with sequences of types is organised into three layers:
- simple tasks can be solved with the standard facilities of the language,
  using pattern match with variadic template specialisations
- the ''type-sequence'' construct `Types<T...>` takes the centre stage
  for the explicit definition of collections of types; it can be re-bound
  to other variadic templates and supports simple direct manipulation
- for more elaborate and advanced processing tasks, a ''Loki-style type list''
  can be obtained from a type-sequence, allowing to perform recursive
  list processing task with a technique similar to LISP.
2025-06-07 18:04:59 +02:00

147 lines
4.4 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Generator(Test) - build an interface + implementation directed by a typelis
Copyright (C)
2008, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
* *****************************************************************/
/** @file generator-test.cpp
** \par what are we doing here??
**
** the following test composes both an interface and the corresponding implementation
** by instantiating "building block" templates over a collection of types. The resulting
** class ends up inheriting a \e virtual function instantiated for each of the types
** in the list. (remember: normally the number and signature of all virtual functions
** need to be absolutely fixed in the class definition)
**
** @see typelist-test.cpp
** @see generator.hpp
** @see lumiera::query::ConfigRules a real world usage example
**
*/
#include "lib/test/run.hpp"
#include "lib/format-string.hpp"
#include "lib/meta/generator.hpp"
#include <iostream>
#include <string>
using util::_Fmt;
using std::string;
using std::cout;
// GCC > 13 warns at class definition when a new overload shadows an inherited virtual function.
// While theoretically correct, this warning is besides the point when an interface is assembled
// by metaprogramming from a chain of template instantiations, driven by a type list
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109740
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"")
namespace lib {
namespace meta {
namespace test {
/** template for generating lots of different test types */
template<int I>
struct Block
{
static string name;
string talk() { return "__"+name+"__"; }
};
template<int I>
string Block<I>::name = _Fmt("Block<%2i>") % I;
/** Use this building block for assembling an abstract interface */
template<class X>
class TakeIt
{
public:
virtual void eat (X& x) = 0;
virtual ~TakeIt() { }
};
/** Use this building block for chaining corresponding implementation classes. */
template<class X, class BASE>
class DoIt
: public BASE
{
protected:
DoIt () { cout << "ctor DoIt<"<< X::name << " >\n";}
virtual ~DoIt() { cout << "dtor DoIt<"<< X::name << " >\n";}
public:
void eat (X& x) { cout << "devouring" << x.talk() << "\n";}
using BASE::eat; // prevent shadowing
};
using TheTypes = Types< Block<1>
, Block<2>
, Block<3>
, Block<5>
, Block<8>
, Block<13>
>::List;
typedef InstantiateForEach<TheTypes,TakeIt> TheInterface;
struct BaseImpl : public TheInterface
{
void eat() { cout << "gulp!\n"; }
};
typedef InstantiateChained<TheTypes,DoIt, BaseImpl> NumberBabbler;
/*********************************************************************//**
* @test check the helpers for dealing with lists-of-types.
* Build an interface and an implementation class
* by inheriting template instantiations
* for a collection of classes</li>
*/
class TypeListGenerator_test : public Test
{
virtual void
run (Arg)
{
NumberBabbler me_can_has_more_numberz;
CHECK (INSTANCEOF (TheInterface, &me_can_has_more_numberz));
TheTypes::Tail::Head b2; // Block<2>
TheTypes::Tail::Tail::Tail::Head b5; // Block<5>
TheTypes::Tail::Tail::Tail::Tail::Tail::Head b13; // Block<13>
me_can_has_more_numberz.eat (b2);
me_can_has_more_numberz.eat (b5);
TakeIt<Block<13>>& subInterface = me_can_has_more_numberz;
subInterface.eat (b13);
me_can_has_more_numberz.eat();
INFO (test, "SizeOf = %zu", sizeof(me_can_has_more_numberz));
}
};
/** Register this test class... */
LAUNCHER (TypeListGenerator_test, "unit common");
}}} // namespace lib::meta::test