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