How to create a simple version of std::function class - c++

Suppose that I want to create a simple version ofstd::function, which has following behaviors:
1. function(){} -> A void constructor
2. function(_ReturnType, Args... vlist) -> To convert function pointer to a funcion object
3. _ReturnType operator() (_ArgTypes... vlist) -> To call function by fn(Args...)
I have already tried to write down a version, but it seems to fail during compiling...
I design it like this:
template <typename ReType, typename... _ArgTypes>
class function
{
protected:
ReType(*fn) = NULL;
public:
function() {}
function(ReType R, _ArgTypes... vlist) { fn = R; }
ReType operator()(_ArgTypes... vlist)
{
return fn(vlist...);
}
};
With compiler error:
In file included from main.cpp:11:
functional.h: In instantiation of 'class nuts::function<double(double)>':
main.cpp:102:27: required from here
functional.h:16:16: error: function returning a function
ReType operator()(_ArgTypes... vlist)
^~~~~~~~
main.cpp: In function 'int main()':
main.cpp:103:19: error: no match for call to '(nuts::function<double(double)>) (double)'
std::cout << fn(2.0) << std::endl;
^

Based on the solution given by #mch
template <typename FuncType>
class function
{
FuncType *(fn) = NULL;
public:
function(FuncType R) : fn{R} {}
template <typename... _ArgTypes>
auto operator()(_ArgTypes... vlist)
{
return fn(vlist...);
}
};

Related

c++ type traits : ensuring a subclass implements a method

There is a virtual class C.
I would like to ensure that any concrete subclass inheriting from C implements a function "get" (and have a clear compile time error if one does not)
Adding a virtual "get" function to C would not work in this case, as C subclasses could implement get functions of various signatures.
(in the particular case I am working on, pybind11 will be used to creates bindings of the subclasses, and pybind11 is robust of the "get" method of B to have a wide range of signatures)
Checking at compile time if a class has a function can be done with type traits, e.g.
template<class T>
using has_get =
decltype(std::declval<T&>().get(std::declval<int>()));
My question is where in the code should I add a static assert (or smthg else) to check the existence of the "get" function. Ideally, this should be part of C declaration, as things should be easy for new user code inheriting from it. It may also be that a completely different approach would be better, which I'd like to hear.
Not sure what standard you are using but with C++20 you can do something like this using concepts
template<typename T>
concept HasGet = requires (T a)
{
a.get();
};
template<HasGet T>
void foo(T x)
{
x.get();
}
struct Foo
{
int get() {
return 1;
}
};
struct Bar
{
};
int main()
{
foo(Foo{});
foo(Bar{});
}
Error:
<source>: In function 'int main()':
<source>:27:12: error: use of function 'void foo(T) [with T = Bar]' with unsatisfied constraints
27 | foo(Bar{});
| ^
<source>:8:6: note: declared here
8 | void foo(T x)
| ^~~
<source>:8:6: note: constraints not satisfied
<source>: In instantiation of 'void foo(T) [with T = Bar]':
<source>:27:12: required from here
<source>:2:9: required for the satisfaction of 'HasGet<T>' [with T = Bar]
<source>:2:18: in requirements with 'T a' [with T = Bar]
<source>:4:9: note: the required expression 'a.get()' is invalid
4 | a.get();
EDIT:
As C++14 is preferred, if I understand you requirements, this is something you can do in C++14
#include <type_traits>
#include <utility>
using namespace std;
template<typename... Ts>
using void_t = void;
template<typename T, typename = void>
struct has_get
: false_type
{};
template<typename T>
struct has_get<T, void_t<decltype(declval<T>().get())>>
: true_type
{};
template<typename T>
static constexpr auto has_get_v = has_get<T>::value;
struct P
{
};
struct C1 : P
{
int get()
{
return 1;
}
};
struct C2 : P
{
float get()
{
return 1.0F;
}
};
struct C3
{
bool get()
{
return true;
}
};
template<typename T>
enable_if_t<is_base_of<P, decay_t<T>>::value && has_get_v<decay_t<T>>> foo(T x)
{
x.get();
}
int main()
{
foo(C1{});
foo(C2{});
foo(C3{});
}
ERROR:
<source>: In function 'int main()':
<source>:61:11: error: no matching function for call to 'foo(C3)'
61 | foo(C3{});
| ^
<source>:52:77: note: candidate: 'template<class T> std::enable_if_t<(std::is_base_of<P, typename std::decay<_Tp>::type>::value && has_get<typename std::decay<_Tp>::type>::value)> foo(T)'
52 | enable_if_t<is_base_of<P, decay_t<T>>::value && has_get<decay_t<T>>::value> foo(T x)
| ^~~
<source>:52:77: note: template argument deduction/substitution failed:
In file included from <source>:1:
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = void]':
<source>:52:77: required by substitution of 'template<class T> std::enable_if_t<(std::is_base_of<P, typename std::decay<_Tp>::type>::value && has_get<typename std::decay<_Tp>::type>::value)> foo(T) [with T = C3]'
<source>:61:11: required from here
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/type_traits:2554:11: error: no type named 'type' in 'struct std::enable_if<false, void>'
2554 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;

How to pass a template method as a template argument?

I would like to pass a template method as a template argument.
I don't understand why I am getting this error:
no known conversion for argument 1 from '<unresolved overloaded function type>' to 'void (B::*&&)(int&&, double&&)
Here is the code:
struct A {
template <class Fn, class... Args>
void f(Fn&& g, Args&&... args) {
g(std::forward<Args>(args)...);
}
};
struct B {
template <class... Args>
void doSomething(Args&&... args) {}
void run() {
A a;
a.f(&doSomething<int, double>, 1, 42.); // error here
}
};
int main() {
B b;
b.run();
return 0;
}
Any ideas?
The root cause for the error is that you need an object to call the member function. However, with current code, the error is not that straightforward.
Change calling site to
a.f(&B::doSomething<int, double>, 1, 42.)
And you will see much better error:
error: must use '.' or '->' to call pointer-to-member function in 'g
(...)', e.g. '(... ->* g) (...)'
doSomething is a member function, as such, it cannot be called without an object, which you are trying to do
g(std::forward<Args>(args)...);
^
where is the instance?
One solution to this is to wrap doSomething in a lambda:
a.f([](B& instance, int a, int b) { instance.doSomething(a, b); }, *this, 1, 42.);
If you can use C++17, you could also use std::invoke:
template <class Fn, class... Args>
void f(Fn&& g, Args&&... args) {
std::invoke(g, std::forward<Args>(args)...);
}
and then when calling f:
a.f(&B::doSomething<int, double>, this, 1, 42.);

Pass a templatized type to a member function in C++

I'm trying to write a member function that can instantiate an object of a custom type (templatized), initializing its const& member to a local object of the function.
This is consistent since the lifetime of the custom type object is the same as the local_object.
The objective is caching some metadata of the local object because they don't change during its lifetime. The operator() (or any member function) computes some values, then used later in func, and the objective is offering a hook to change the behaviour of func.
Please no polymorphic solutions (currently used) due to (profiled) slowness.
This is a M(N)WE:
#include <vector>
class cls {
public:
template <typename Custom> int func() {
std::vector<int> local_object{0, 14, 32};
Custom c(local_object, 42);
return c();
}
};
template<typename AType> class One {
public:
One(const AType& obj, const int n): objref(obj), param(n), member_that_should_depend_on_objref(obj.size()) {}
int operator()() { return 42; }
private:
const AType& objref;
const int param;
float member_that_should_depend_on_objref;
};
template<typename AType> class Two {
public:
Two(const AType& obj, const int n): objref(obj), param(n), other_member_that_should_depend_on_objref(obj.empty()), other_dependent_member(obj.back()) {}
int operator()() { return 24; }
private:
const AType& objref;
const int param;
bool other_member_that_should_depend_on_objref;
int other_dependent_member;
};
int main() {
cls myobj;
auto a = myobj.func<One>();
auto b = (myobj.func<Two>)();
}
G++ 5.3.0 says
tmp.cpp: In function 'int main()':
tmp.cpp:34:30: error: no matching function for call to 'cls::func()'
auto a = myobj.func<One>();
^
tmp.cpp:4:36: note: candidate: template<class Custom> int cls::func()
template <typename Custom> int func() {
^
tmp.cpp:4:36: note: template argument deduction/substitution failed:
tmp.cpp:35:32: error: no matching function for call to 'cls::func()'
auto b = (myobj.func<Two>)();
^
tmp.cpp:4:36: note: candidate: template<class Custom> int cls::func()
template <typename Custom> int func() {
^
tmp.cpp:4:36: note: template argument deduction/substitution failed:
Clang++ 3.7.1 says:
tmp.cpp:34:20: error: no matching member function for call to 'func'
auto a = myobj.func<One>();
~~~~~~^~~~~~~~~
tmp.cpp:4:36: note: candidate template ignored: invalid explicitly-specified argument for template
parameter 'Custom'
template <typename Custom> int func() {
^
tmp.cpp:35:21: error: no matching member function for call to 'func'
auto b = (myobj.func<Two>)();
~~~~~~~^~~~~~~~~~
tmp.cpp:4:36: note: candidate template ignored: invalid explicitly-specified argument for template
parameter 'Custom'
template <typename Custom> int func() {
^
2 errors generated.
auto a = myobj.func<One>();
is wrong since One is a class template, not a class. Use
auto a = myobj.func<One<SomeType>>();
It's not clear from your code what SomeType should be.
Update
If you want to use:
auto a = myobj.func<One>();
you need to change func to use a template template parameter:
class cls {
public:
template <template <class> class Custom > int func() {
std::vector<int> local_object{0, 14, 32};
Custom<std::vector<int>> c(local_object, 42);
return c();
}
};
Perhaps that was your intention.

Unresolved overloaded function type when attempting to pass a function as an argument

I receive the following error when attempting to compile a lone C++ testing file under G++ with C++11 in place.
spike/cur_spike.cpp: In function ‘int main()’:
spike/cur_spike.cpp:60:44: error: no matching function for call to ‘callFunctionFromName(<unresolved overloaded function type>, std::__cxx11::string&)’
callFunctionFromName (outputLine, param);
^
spike/cur_spike.cpp:49:7: note: candidate: template<class funcT, class ... Args> funcT callFunctionFromName(funcT (*)(Args ...), Args ...)
funcT callFunctionFromName (funcT func(Args...), Args... args) {
^
spike/cur_spike.cpp:49:7: note: template argument deduction/substitution failed:
spike/cur_spike.cpp:60:44: note: couldn't deduce template parameter ‘funcT’
callFunctionFromName (outputLine, param);
^
Here's the code.
#include <iostream>
#include <string>
template <typename T>
void outputLine (T text) {
std::cout << text << std::endl;
}
template <typename funcT>
funcT callFunctionFromName (funcT func()) {
return func ();
}
template <typename funcT, typename... Args>
funcT callFunctionFromName (funcT func(Args...), Args... args) {
return func (args...);
}
int main () {
std::string param = "Testing...";
callFunctionFromName (outputLine, param);
return 0;
}
I'm currently building this on a Linux system using G++, this code snippet contains all code related to this issue. I'm particularly intrigued about the fact that the compiler is unable to deduce the template parameter funcT for some reason, even though the outputLine function has a clear return type of void.
Setting a pointer of outputLine using void (*outputLinePtr)(std::string) = outputLine and using the pointer as the argument instead does nothing. Any help would be much appreciated.
You can manually set template argument.
callFunctionFromName (outputLine<std::string>, param);

Thread C++ member function template variadic template

I try to call a member function of an object using a thread.
If the function doesn't have a variadic template (Args ... args), no problem, it works:
Consider the two classes:
GeneticEngine
template <class T>
class GeneticEngine
{
template <typename ... Args>
T* run_while(bool (*f)(const T&),const int size_enf,Args& ... args)
{
std::thread(&GeneticThread<T>::func,islands[0],f,size_enf);
/* Some code */
return /* ... */
}
private:
GeneticThread<T>** islands;
}
GeneticThread
template <class T>
class GeneticThread
{
void func(bool (*f)(const T&),const int size_enf)
{
/* Some code */
};
}
With this, it's OK.
Now, I add a variadic template to the same functions:
GeneticEngine
template <class T>
class GeneticEngine
{
template <typename ... Args>
T* run_while(bool (*f)(const T&,Args& ...),const int size_enf,Args& ... args)
{
std::thread(&GeneticThread<T>::func,islands[0],f,size_enf,args ...);
/* Other code ... */
}
private:
GeneticThread<T>** islands;
}
GeneticThread
template <class T>
class GeneticThread
{
template <typename ... Args>
void func(bool (*f)(const T&,Args& ...), const int size_enf, Args& ... args)
{
/* Code ... */
};
}
With this code, GCC doesn't compile: (sorry for this error message)
g++ main.cpp GeneticEngine.hpp GeneticThread.hpp Individu.hpp GeneticThread.o -g -std=c++0x -o main.exe
In file included from main.cpp:2:0:
GeneticEngine.hpp: In instantiation of ‘T* GeneticEngine<T>::run_while(bool (*)(const T&, Args& ...), int, Args& ...) [with Args = {}; T = Individu]’:
main.cpp:24:78: required from here
GeneticEngine.hpp:20:13: erreur: no matching function for call to ‘std::thread::thread(<unresolved overloaded function type>, GeneticThread<Individu>*&, bool (*&)(const Individu&), const int&)’
GeneticEngine.hpp:20:13: note: candidates are:
In file included from GeneticThread.hpp:14:0,
from GeneticEngine.hpp:4,
from main.cpp:2:
/usr/include/c++/4.7/thread:131:7: note: template<class _Callable, class ... _Args> std::thread::thread(_Callable&&, _Args&& ...)
/usr/include/c++/4.7/thread:131:7: note: template argument deduction/substitution failed:
In file included from main.cpp:2:0:
GeneticEngine.hpp:20:13: note: couldn't deduce template parameter ‘_Callable’
In file included from GeneticThread.hpp:14:0,
from GeneticEngine.hpp:4,
from main.cpp:2:
/usr/include/c++/4.7/thread:126:5: note: std::thread::thread(std::thread&&)
/usr/include/c++/4.7/thread:126:5: note: candidate expects 1 argument, 4 provided
/usr/include/c++/4.7/thread:122:5: note: std::thread::thread()
/usr/include/c++/4.7/thread:122:5: note: candidate expects 0 arguments, 4 provided
I really do not understand why this difference makes this error. And I can not fix it.
In both the main.cpp is like that:
/* Individu is another class */
int pop_size = 1000;
int pop_child = pop_size*0.75;
GeneticEngine<Individu> engine(/*args to constructor*/);
bool (*stop)(const Individu&) = [](const Individu& best){
return false;
};
Individu* best = engine.run_while(stop,pop_child);
I use : «gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1) »
I tried:
std::thread(&GeneticThread<T>::func<Args...>, islands[0], f, size_enf, args ...);
Now I have another error:
GeneticEngine.hpp: In member function ‘T* GeneticEngine<T>::run_while(bool (*)(const T&, Args& ...), int, Args& ...)’:
GeneticEngine.hpp:20:53: erreur: expansion pattern ‘((& GeneticThread<T>::func) < <expression error>)’ contains no argument packs
GeneticEngine.hpp:20:24: erreur: expected primary-expression before ‘(’ token
GeneticEngine.hpp:20:53: erreur: expected primary-expression before ‘...’ token
template <typename ... Args>
T* run_while(bool (*f)(const T&,Args& ...), const int size_enf, Args& ... args)
{
void (GeneticThread<T>::*ptm)(bool (*)(T const&, Args&...), int, Args&...) = &GeneticThread<T>::func;
std::thread(ptm, islands[0], f, size_enf, args ...);
}
Try:
std::thread(&GeneticThread<T>::func<Args...>, islands...
func is now a template function. You have to specify its template parameters to be able to take its address.