Browse Source
Added: template function which uses as many arguments to a callable object as possible
main
Added: template function which uses as many arguments to a callable object as possible
main
4 changed files with 179 additions and 0 deletions
-
16invoke-callable/Makefile
-
4invoke-callable/README.md
-
92invoke-callable/invoke_callable.hpp
-
67invoke-callable/main.cpp
@ -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 |
||||
@ -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. |
||||
@ -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
|
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue