Browse Source

Added: template function which uses as many arguments to a callable object as possible

main
andpal@linlap 4 years ago
parent
commit
2570bfaa79
  1. 16
      invoke-callable/Makefile
  2. 4
      invoke-callable/README.md
  3. 92
      invoke-callable/invoke_callable.hpp
  4. 67
      invoke-callable/main.cpp

16
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

4
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.

92
invoke-callable/invoke_callable.hpp

@ -0,0 +1,92 @@
#ifndef _INVOKE_CALLABLE
#define _INVOKE_CALLABLE
#include <type_traits>
#include <concepts>
#include <array> // 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<class Callable, class T>
concept TriArg =
requires(Callable c, T t, std::size_t n) {
c(t, n, n);
};
template<class Callable, class T>
concept DuoArg =
!TriArg<Callable, T>
&& requires(Callable c, T t, std::size_t n) {
c(t, n);
};
template<class Callable, class T>
concept UniArg =
!TriArg<Callable, T>
&& !DuoArg<Callable, T>
&& requires(Callable c, T t) {
c(t);
};
/*
* Functions invoking Callable with actual arguments.
* Constrained by the n-argument Concepts above.
*/
template<class Callable, class T>
typename std::enable_if< TriArg<Callable, T>, void>::type
invoke_on_callable(Callable c, T elem, std::size_t index, std::size_t size)
{
c(elem, index, size);
}
template<class Callable, class T>
typename std::enable_if< DuoArg<Callable, T>, void >::type
invoke_on_callable(Callable c, T elem, std::size_t index, std::size_t)
{
c(elem, index);
}
template<class Callable, class T>
typename std::enable_if< UniArg<Callable, T>, void >::type
invoke_on_callable(Callable c, T elem, std::size_t, std::size_t)
{
c(elem);
}
/*
* enumerate()
*/
template<class Container, class Callable>
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

67
invoke-callable/main.cpp

@ -0,0 +1,67 @@
#include "invoke_callable.hpp"
#include <iostream>
#include <vector>
/*
* Solution to assignement 6 from exam: TDDD38-220113
*/
// A few test objects
template<class T>
struct A
{
void operator() (T elem) {
std::cout
<< "UniCallable( "
<< elem << " )"
<< std::endl;
}
};
template<class T>
struct B
{
void operator() (T elem, size_t index) {
std::cout
<< "DuoCallable( "
<< elem << ", "
<< index << " )" << std::endl;
}
};
template<class T>
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<int> ao;
B<int> bo;
C<int> co;
enumerate(arr, ao);
puts("");
enumerate(arr, bo);
puts("");
enumerate(arr, co);
}
}
Loading…
Cancel
Save