From 2570bfaa796dff5ad70e77aa3227c8327b9dd10d Mon Sep 17 00:00:00 2001 From: "andpal@linlap" Date: Mon, 28 Feb 2022 21:38:08 +0100 Subject: [PATCH] Added: template function which uses as many arguments to a callable object as possible --- invoke-callable/Makefile | 16 +++++ invoke-callable/README.md | 4 ++ invoke-callable/invoke_callable.hpp | 92 +++++++++++++++++++++++++++++ invoke-callable/main.cpp | 67 +++++++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 invoke-callable/Makefile create mode 100644 invoke-callable/README.md create mode 100644 invoke-callable/invoke_callable.hpp create mode 100644 invoke-callable/main.cpp diff --git a/invoke-callable/Makefile b/invoke-callable/Makefile new file mode 100644 index 0000000..63696a4 --- /dev/null +++ b/invoke-callable/Makefile @@ -0,0 +1,16 @@ +EXE=invoker +CC=clang++ +CFLAGS=-g -O2 -std=c++20 -Wall -Wextra + +.PHONY: test, clean +test: $(EXE) + ./$(EXE) + +$(EXE): main.cpp invoke_callable.hpp.gch + $(CC) $(CFLAGS) -o $(EXE) main.cpp + +invoke_callable.hpp.gch: invoke_callable.hpp + $(CC) $(CFLAGS) -c invoke_callable.hpp + +clean: + rm -rf $(EXE) ./*.o ./*.gch diff --git a/invoke-callable/README.md b/invoke-callable/README.md new file mode 100644 index 0000000..68b3431 --- /dev/null +++ b/invoke-callable/README.md @@ -0,0 +1,4 @@ +# Invoke callable # +Specifies a function enumerate() which will use the template version +of itself which uses the operator() with the most arguments available +in the class. diff --git a/invoke-callable/invoke_callable.hpp b/invoke-callable/invoke_callable.hpp new file mode 100644 index 0000000..326a7a1 --- /dev/null +++ b/invoke-callable/invoke_callable.hpp @@ -0,0 +1,92 @@ +#ifndef _INVOKE_CALLABLE +#define _INVOKE_CALLABLE + +#include +#include + +#include // Only for std::size() + + +/* + * This file defines the function: + * enumerate( + * Container container, + * Callable callable + * ) + * The enumerate function will iterate over all elements in the container + * calling the callable object with as many arguments as possible: + * callable(*it, index, sized) + * callable(*it, index) + * callable(*it) + */ + + + +/* + * Concepts filtering Callable objects by the most arguments + * their operator() takes. + */ +template +concept TriArg = + requires(Callable c, T t, std::size_t n) { + c(t, n, n); + }; + +template +concept DuoArg = + !TriArg + && requires(Callable c, T t, std::size_t n) { + c(t, n); + }; + +template +concept UniArg = + !TriArg + && !DuoArg + && requires(Callable c, T t) { + c(t); + }; + + +/* + * Functions invoking Callable with actual arguments. + * Constrained by the n-argument Concepts above. + */ +template +typename std::enable_if< TriArg, void>::type + invoke_on_callable(Callable c, T elem, std::size_t index, std::size_t size) +{ + c(elem, index, size); +} + +template +typename std::enable_if< DuoArg, void >::type + invoke_on_callable(Callable c, T elem, std::size_t index, std::size_t) +{ + c(elem, index); +} + +template +typename std::enable_if< UniArg, void >::type + invoke_on_callable(Callable c, T elem, std::size_t, std::size_t) +{ + c(elem); +} + + + +/* + * enumerate() + */ +template +void enumerate(Container const& container, Callable callable) +{ + std::size_t i{0}; + std::size_t size{ std::size(container) }; + + for (auto item : container) { + invoke_on_callable(callable, item, i++, size); + } +} + +#endif diff --git a/invoke-callable/main.cpp b/invoke-callable/main.cpp new file mode 100644 index 0000000..a077f96 --- /dev/null +++ b/invoke-callable/main.cpp @@ -0,0 +1,67 @@ +#include "invoke_callable.hpp" +#include +#include + +/* + * Solution to assignement 6 from exam: TDDD38-220113 + */ + + +// A few test objects +template +struct A +{ + void operator() (T elem) { + std::cout + << "UniCallable( " + << elem << " )" + << std::endl; + } +}; + +template +struct B +{ + void operator() (T elem, size_t index) { + std::cout + << "DuoCallable( " + << elem << ", " + << index << " )" << std::endl; + } +}; + +template +struct C +{ + void operator() (T elem, size_t index, size_t size) { + std::cout + << "TriCallable( " + << elem << ", " + << index << ", " + << size << " )" << std::endl; + } + void operator() (T) { + fputs("ERROR: one-arg function called on three-arg capable object!\n", stderr); + } +}; + + +int main() +{ + // Passing callable objects with different configurations of + // operator() to enumerate() + { + std::vector arr{3,8,6,3}; + A ao; + B bo; + C co; + + enumerate(arr, ao); + + puts(""); + enumerate(arr, bo); + + puts(""); + enumerate(arr, co); + } +}