How can I determine whether a function's parameter type is a function? I'm implementing a class called Queue which receives a single parameter. If the parameter is a function, it stores the function.
Here is the code:
template <class Type, typename Data>
class Queue {
public:
void Enqueue (Data& data) {
if (typeid(data).name() == int) {
intVector.push_back(data);
order.push_back("int");
}
else if (typeid(data).name() == bool) {
boolVector.push_back(data);
order.push_back("bool");
}
else if (typeid().name() == string) {
stringVector.push_back(data);
order.push_back("string");
}
// This will continue for:
// - double
// - char
// - function
}
auto Dequeue () {
auto temp;
switch (order.begin()) {
case "int":
temp = intVector.begin();
intVector.erase(intVector.begin());
order.erase(order.begin());
return temp;
// This will continue for:
// - "string"
// - "bool"
// - "char"
// - "double"
// - "function"
default:
cout << "An Error occurred while trying to Enqueue." << endl;
cout << "\tAddress: " << this << endl;
}
}
auto Start () {
// This function will run all of the processes...
}
Queue (Data& data) {
if (typeid(Type).name() == int) {
// Pseodo-code:
// if (data.type == function) {
// Enqueue (data);
// }
}
}
}
It can be initialised:
Queue queue1 = new Queue <int> (func ()); // func () is a function.
Queue queue2 = new Queue <int> (var); // var is a variable.
Oh my. This is a bit of an XY problem.
Anyway, after messing around with std::enable_if for a bit (which was kinda fun), I realised that the whole thing can be boiled down to this:
#include <vector>
#include <string>
#include <any>
#include <iostream>
#include <functional>
void call_if_function (void (* f) ()) { f (); }
void call_if_function (std::function <void ()> f) { f (); }
void call_if_function (std::any x) { (void) x; }
template <class T>
class Queue
{
public:
void Enqueue (const T& data)
{
// std::cout << "Enqueueing " << data << "\n";
v.push_back (data);
}
T Dequeue ()
{
T ret = v.front ();
// std::cout << "Dequeueing " << ret << "\n";
v.erase (v.begin ());
call_if_function (ret);
return ret;
}
private:
std::vector <T> v;
};
And, if I understand the OP's problem right, that is all all you need.
Test program:
void foo () { std::cout << "foo () called\n"; }
void bar (int x, int y) { std::cout << "bar () called, x = " << x << ", y = " << y << "\n"; }
int main ()
{
// Queue of int's
Queue <int> int_q;
int_q.Enqueue (42);
auto i = int_q.Dequeue ();
std::cout << "int_q.Dequeue () returned " << i << "\n\n";
// Queue of strings
Queue <std::string> string_q;
string_q.Enqueue ("Hello world");
auto s = string_q.Dequeue ();
std::cout << "string_q.Dequeue () returned " << s << "\n\n";
// Call function with no parameters
Queue <void (*)()> func_q;
func_q.Enqueue (foo);
auto f = func_q.Dequeue ();
std::cout << "func_q.Dequeue () returned " << (void *) f << "\n";
f ();
// Call function with arbitrary parameters
Queue <std::function <void ()>> func_qp;
func_qp.Enqueue ([] () { bar (21, 99); });
auto fp = func_qp.Dequeue ();
fp ();
}
Output:
int_q.Dequeue () returned 42
string_q.Dequeue () returned Hello world
foo () called
func_q.Dequeue () returned 0x4026fd
foo () called
bar () called, x = 21, y = 99
bar () called, x = 21, y = 99
Live demo.
Moral: KISS, there are far too many toys in the toybox these days. Enjoy the weekend people.
And, since I took the time to research it a bit (mainly because I wanted to learn a bit about it), here is a bit of super-simple SFINAE cobbled together from the wise ones.
#include <type_traits>
#include <iostream>
// Primary template (required)
template <class T, class Enable = void>
struct X { };
// Specialisation to take a function pointer
template <class T>
struct X <T, typename std::enable_if <std::is_function<T>::value>::type>
{
X (T func)
{
std::cout << "T is a function\n";
func ();
}
};
// Partial specialisation for anything else
template<class T>
struct X <T, typename std::enable_if <!std::is_function<T>::value>::type>
{
X (T x)
{
std::cout << "T is not a function (and x is " << x << ")\n";
}
};
void foo () { std::cout << "foo () called\n"; }
int main ()
{
X <void ()> x1 (foo);
X <int> x2 (42);
}
Output:
T is a function
foo () called
T is not a function (and x is 42)
Live demo.
Powerful stuff, but not the answer to every little problem.
How can I determine whether a function's parameter type is a function?
You can use the std::is_function to do that.
An implementation like
template <class Type, typename Data>
class Queue {
public:
Queue (Data& data) {
if (typeid(Type).name() == int) {
// Pseodo-code:
if (std::is_function<data.type>::value) {
Enqueue (data);
}
}
}
}
won't work though, since the part inside the if block scope is seen for other data types by the compiler.
To realize that you'll need to use SFINAE, and provide different specializations of your Queue constructor function using std::enable_if.
For a SFINAE example:
Queue(std::enable_if_t<std::is_function_v<Data>, Data>::type & data)
{
//data is a function
}
//I'm not sure if the enable_if is needed here, maybe you can just do Data& data
Queue(std::enable_if_t<!std::is_function_v<Data>, Data>::type & data)
{
//data is not a function
}
(You need to include <type_traits> to use std::is_function_v)
Related
So I had this scenario where I want to call either function of a class, where the function in question has the same prototype but it's also overloaded. Since I know of pointer to members my immediate reaction was something like this:
struct test
{
int overloaded(char) {}
int overloaded(int) {}
int overloadedone(char) {}
int overloadedone(int) {}
} test;
int main()
{
(test.*(true ? (&test::overloaded) : (&test::overloadedone)))(1);
}
However it turned out the compiler (MSVC - 2019 Preview latest version with std C++ preview) can't deduce the type and I have to write:
(test.*(true ? static_cast<int (test::*)(int)>(&test::overloaded) : static_cast<int (test::*)(int)>(&test::overloadedone)))(1);
instead which made me return to the good old:
true ? test.overloaded(1) : test.overloadedone(1);
But I wonder if this is the defined behavior of requiring those cast. Even:
(test.*static_cast<int (test::*)(int)>(true ? (&test::overloaded) : (&test::overloadedone)))(1);
Doesn't work.
You have to write said cast on each of the two possibilities for the ternary as in the second example.
It isn't particularly elegant, but this approach can deduce an overload if you curry the member function pointer's arguments before passing the member function pointers themselves:
#include <iostream>
template <class... Args>
auto invoke_conditional_mem_fn(Args... args)
{
return [=] <class R, class X> (X x, bool b, R(X::*t)(Args...), R(X::*f)(Args...)) -> R
{
return (x.*(b ? t : f))(args...);
};
}
struct test
{
int overloaded(char) { std::cout << "overloaded(char) "; return 1; }
int overloaded(int) { std::cout << "overloaded(int) "; return 2; }
int overloadedone(char) { std::cout << "overloadedone(char) "; return 3; }
int overloadedone(int) { std::cout << "overloadedone(int) "; return 4; }
} test;
int main()
{
std::cout
<< invoke_conditional_mem_fn('1')(test, true, &test::overloaded, &test::overloadedone)
<< std::endl
<< invoke_conditional_mem_fn(1)(test, false, &test::overloaded, &test::overloadedone)
<< std::endl;
}
Thanks to #dyp and their example, we know that we can infer the return type and base of the member function pointers if we select which arguments to pass.
Alternatively, you could do something a little simpler like this, if it meets your needs. Just declare a lambda to work around the limitations of your ternary expression with an if and else statement since each branch of a ternary operator is required to be of the same type.
#include <iostream>
struct test
{
int overloaded(char) { std::cout << "overloaded(char) "; return 1; }
int overloaded(int) { std::cout << "overloaded(int) "; return 2; }
int overloadedone(char) { std::cout << "overloadedone(char) "; return 3; }
int overloadedone(int) { std::cout << "overloadedone(int) "; return 4; }
} test;
auto conditional = [] (struct test& test, bool cond, auto... args)
{
if (cond) return test.overloaded(args...);
else return test.overloadedone(args...);
};
int main()
{
std::cout << conditional(test, true, '1') << std::endl;
std::cout << conditional(test, false, 1) << std::endl;
}
Let's say I multiple functions with variable arguments:
void greetWorld() {
cout << "Hello World!" << endl;
}
void greetName(const string& name) {
cout << "Hello " << name << "!" << endl;
}
void printAddition(const int lhs, const int rhs) {
cout << "Addition: " << to_string(lhs + rhs) << endl;
}
And these are stored in a map of std::strings to functions (functions being stored as a polymorphic class).
template<typename... Args>
class DerivedFunction;
class BaseFunction {
public:
template<typename... Args>
void operator()(Args... args) const {
(*static_cast<const DerivedFunction<Args...>*>(this))(args...);
}
};
template<typename... Args>
class DerivedFunction : public BaseFunction {
public:
DerivedFunction(void(*function)(Args...)) {
this->function = function;
}
void operator()(Args... args) const {
function(args...);
}
private:
void(*function)(Args...);
};
template<typename... Args>
unique_ptr<DerivedFunction<Args...>> make_function(
void(*function)(Args...)
) {
return std::make_unique<DerivedFunction<Args...>>(function);
}
int main() {
unordered_map<string, unique_ptr<BaseFunction>> function_map;
function_map.insert({ "greetWorld", make_function(&greetWorld) });
function_map.insert({ "greetName", make_function(&greetName) });
function_map.insert({ "printAddition", make_function(&printAddition) });
...
}
I can call the functions at compile time like:
int main() {
...
(*function_map.at("greetWorld"))();
(*function_map.at("greetName"))("Foo"s);
(*function_map.at("printAddition"))(1, 2);
}
If I then have a string, or stream like:
greetWorld
greetName string Foo
printAddition int 1 int 2
What would be a good way to call the functions?
I can not figure out any way to cast a type at runtime.
Why?
I am trying to implement some kind of remote call procedure for learning purposes. I do not want to use an external library as I am trying to learn how to implement this with the C++ standard library for the sake of understanding C++ more.
What have I tried?
Not much. I've tested creating functions that take a std::vector of std::anys as an argument, and then had the function any_cast them to the type they are. Whilst this does work, it does not look nice, it requires duplicates of all functions, I would rather be able to write functions with meaningful arguments than ambigious.
Minimum Example
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
using namespace std;
void greetWorld() {
cout << "Hello World!" << endl;
}
void greetName(const string& name) {
cout << "Hello " << name << "!" << endl;
}
void printAddition(const int lhs, const int rhs) {
cout << "Addition: " << to_string(lhs + rhs) << endl;
}
template<typename... Args>
class DerivedFunction;
class BaseFunction {
public:
template<typename... Args>
void operator()(Args... args) const {
(*static_cast<const DerivedFunction<Args...>*>(this))(args...);
}
};
template<typename... Args>
class DerivedFunction : public BaseFunction {
public:
DerivedFunction(void(*function)(Args...)) {
this->function = function;
}
void operator()(Args... args) const {
function(args...);
}
private:
void(*function)(Args...);
};
template<typename... Args>
unique_ptr<DerivedFunction<Args...>> make_function(
void(*function)(Args...)
) {
return std::make_unique<DerivedFunction<Args...>>(function);
}
int main() {
unordered_map<string, unique_ptr<BaseFunction>> function_map;
function_map.insert({ "greetWorld", make_function(&greetWorld) });
function_map.insert({ "greetName", make_function(&greetName) });
function_map.insert({ "printAddition", make_function(&printAddition) });
cout << "Calling functions at compile time." << endl << endl;
(*function_map.at("greetWorld"))();
(*function_map.at("greetName"))("Foo"s);
(*function_map.at("printAddition"))(1, 2);
//cout << endl << "Calling functions at runtime." << endl << endl;
//string runtime =
// "greetWorld\n"
// "greetName string Foo\n"
// "printAddition int 1 int 2";
//
// todo: call functions
}
Solved.
If you apply the accepted solution, you can call functions from the text like I had wanted.
Here is new code for an example Tcp server and client. The client sends function names and arguments as a string to the server. The server then executes these. Exactly what I wanted.
struct FunctionNameAndArguments {
string function_name;
vector<RPC> arguments;
};
FunctionNameAndArguments parseFunctionNameAndArguments(
const string& function_name_and_arguments_string
) {
istringstream ss(function_name_and_arguments_string);
FunctionNameAndArguments function_name_and_arguments;
// function name
ss >> function_name_and_arguments.function_name;
// arguments
auto& arguments = function_name_and_arguments.arguments;
while (!ss.eof()) {
string function_type;
ss >> function_type;
// integer
if (function_type == "int") {
int value;
ss >> value;
arguments.push_back(value);
}
// string
else if (function_type == "string") {
string value;
ss >> value;
arguments.push_back(value);
}
else {
throw exception("unknown argument type");
}
}
return function_name_and_arguments;
}
int main() {
unordered_map<string, RPCHandler> functions = {
{ "greetWorld", make_invoker(&greetWorld) },
{ "greetName", make_invoker(&greetName) },
{ "printAddition", make_invoker(&printAddition) }
};
char server;
cout << "Server? (y/n): " << endl;
cin >> server;
// server
if (server == 'y') {
// accept client
TcpListener listen;
listen.listen(25565);
TcpSocket client;
listen.accept(client);
size_t received;
// receive size of string
size_t size;
client.receive(&size, sizeof(size), received);
// receive function name and arguments as string
string function_name_and_arguments_string;
function_name_and_arguments_string.resize(size);
client.receive(
function_name_and_arguments_string.data(),
size,
received
);
// go through each line
istringstream lines(function_name_and_arguments_string);
string line;
while (getline(lines, line)) {
// parse function name and arguments
auto [function_name, arguments] = parseFunctionNameAndArguments(
line
);
// call function
functions.at(function_name)(
arguments
);
}
}
// client
else {
// connect to server
TcpSocket server;
server.connect("localhost", 25565);
// function calls string
const string function_calls =
"greetWorld\n"
"greetName string Foo\n"
"printAddition int 1 int 2";
size_t size = function_calls.size();
// send size of string
server.send(&size, sizeof(size));
// send function calls string
server.send(function_calls.data(), size);
}
}
Let us assume you have a list of types (taking int and string as an example) usable in RPC, we can combine them in a RPC type and associated RPCHandler as follows:
using RPC = std::variant<int, std::string>;
using RPCHandler = std::function<void(std::vector<RPC>)>;
You want to create a std::map<std::string, RPCHandler> dispatch so you can do (given a std::vector<RPC> args):
dispatch[command](args);
This map can be constructed as follows:
void test0();
void test2(int, std::string);
std::map<std::string, RPCHandler> dispatch = {
{ "test0", make_invoker(test0) },
{ "test2", make_invoker(test2) },
};
where make_invoker returns a lambda of the correct shape.
The body of this lambda passes the function pointer, argument vector, and a std::index_sequence to invoke_rpc:
template<class... Arg>
RPCHandler make_invoker(void (*f)(Arg...)) {
return [f](std::vector<RPC> args) {
invoke_rpc(f, args, std::index_sequence_for <Arg...>{});
};
}
Finally, invoke_rpc uses std::get on each argument in turn to convert it into the expected type. It does this by expanding the two given template parameter packs in parallel. Intuitively, this expands to f(std::get<Arg0>(args.at(0), std::get<Arg1>(args.at(1)) with as many arguments to f as it expects (since the index sequence has the same length Args...).
template<class... Arg, std::size_t... I>
void invoke_rpc(void (*f)(Arg...), std::vector<RPC> args, std::index_sequence<I...>) {
f(std::get<Arg>(args.at(I))...);
}
If the vector is too short you get a std::out_of_range error, if there is an argument mismatch you get a std::bad_variant_access. You can improve error handling by checking the size of args before calling f, and using std::holds_alternative to see if all passed values match their proscribed type.
I have some var = std::variant<std::monostate, a, b, c> when a, b, c is some types.
How, at runtime, do I check what type var contains?
In the official documentation I found information that if var contains a type and I write std::get<b>(var) I get an exception. So I thought about this solution:
try {
std::variant<a>(var);
// Do something
} catch(const std::bad_variant_access&) {
try {
std::variant<b>(var);
// Do something else
} catch(const std::bad_variant_access&) {
try {
std::variant<c>(var);
// Another else
} catch (const std::bad_variant_access&) {
// std::monostate
}
}
}
But it's so complicated and ugly! Is there a simpler way to check what type std::variant contains?
std::visit is the way to go:
There is even overloaded to allow inlined visitor:
// helper type for the visitor #4
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
// explicit deduction guide (not needed as of C++20)
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
and so:
std::visit(overloaded{
[](std::monostate&){/*..*/},
[](a&){/*..*/},
[](b&){/*..*/},
[](c&){/*..*/}
}, var);
To use chained if-branches instead, you might used std::get_if
if (auto* v = std::get_if<a>(var)) {
// ...
} else if (auto* v = std::get_if<b>(var)) {
// ...
} else if (auto* v = std::get_if<c>(var)) {
// ...
} else { // std::monostate
// ...
}
The most simple way is to switch based on the current std::variant::index(). This approach requires your types (std::monostate, A, B, C) to always stay in the same order.
// I omitted C to keep the example simpler, the principle is the same
using my_variant = std::variant<std::monostate, A, B>;
void foo(my_variant &v) {
switch (v.index()) {
case 0: break; // do nothing because the type is std::monostate
case 1: {
doSomethingWith(std::get<A>(v));
break;
}
case 2: {
doSomethingElseWith(std::get<B>(v));
break;
}
}
}
If your callable works with any type, you can also use std::visit:
void bar(my_variant &v) {
std::visit([](auto &&arg) -> void {
// Here, arg is std::monostate, A or B
// This lambda needs to compile with all three options.
// The lambda returns void because we don't modify the variant, so
// we could also use const& arg.
}, v);
}
If you don't want std::visit to accept std::monostate, then just check if the index is 0. Once again, this relies on std::monostate being the first type of the variant, so it is good practice to always make it the first.
You can also detect the type using if-constexpr inside the callable. With this approach, the arguments don't have to be in the same order anymore:
void bar(my_variant &v) {
std::visit([](auto &&arg) -> my_variant {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<std::monostate, T>) {
return arg; // arg is std::monostate here
}
else if constexpr (std::is_same_v<A, T>) {
return arg + arg; // arg is A here
}
else if constexpr (std::is_same_v<B, T>) {
return arg * arg; // arg is B here
}
}, v);
}
Note that the first lambda returns void because it just processes the current value of the variant. If you want to modify the variant, your lambda needs to return my_variant again.
You could use an overloaded visitor inside std::visit to handle A or B separately. See std::visit for more examples.
You can use standard std::visit
Usage example:
#include <variant>
#include <iostream>
#include <type_traits>
struct a {};
struct b {};
struct c {};
int main()
{
std::variant<a, b, c> var = a{};
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, a>)
std::cout << "is an a" << '\n';
else if constexpr (std::is_same_v<T, b>)
std::cout << "is a b" << '\n';
else if constexpr (std::is_same_v<T, c>)
std::cout << "is a c" << '\n';
else
std::cout << "is not in variant type list" << '\n';
}, var);
}
Well, with some macro magic, you can do something like:
#include <variant>
#include <type_traits>
#include <iostream>
#define __X_CONCAT_1(x,y) x ## y
#define __X_CONCAT(x,y) __X_CONCAT_1(x,y)
template <typename T>
struct __helper { };
// extract the type from a declaration
// we use function-type magic to get that: typename __helper<void ( (declaration) )>::type
// declaration is "int &x" for example, this class template extracts "int"
template <typename T>
struct __helper<void (T)> {
using type = std::remove_reference_t<T>;
};
#define variant_if(variant, declaration) \
if (bool __X_CONCAT(variant_if_bool_, __LINE__) = true; auto * __X_CONCAT(variant_if_ptr_, __LINE__) = std::get_if<typename __helper<void ( (declaration) )>::type>(&(variant))) \
for (declaration = * __X_CONCAT(variant_if_ptr_, __LINE__); __X_CONCAT(variant_if_bool_, __LINE__); __X_CONCAT(variant_if_bool_, __LINE__) = false)
#define variant_switch(variant) if (auto &__variant_switch_v = (variant); true)
#define variant_case(x) variant_if(__variant_switch_v, x)
int main() {
std::variant<int, long> v = 12;
std::variant<int, long> w = 32l;
std::cout << "variant_if test" << std::endl;
variant_if(v, int &x) {
std::cout << "int = " << x << std::endl;
}
else variant_if(v, long &x) {
std::cout << "long = " << x << std::endl;
}
std::cout << "variant_switch test" << std::endl;
variant_switch(v) {
variant_case(int &x) {
std::cout << "int = " << x << std::endl;
variant_switch (w) {
variant_case(int &x) {
std::cout << "int = " << x << std::endl;
}
variant_case(long &x) {
std::cout << "long = " << x << std::endl;
}
}
};
variant_case(long &x) {
std::cout << "long = " << x << std::endl;
variant_switch (w) {
variant_case(int &x) {
std::cout << "int = " << x << std::endl;
}
variant_case(long &x) {
std::cout << "long = " << x << std::endl;
}
}
};
}
return 0;
}
I tested this approach with GCC and Clang, no guarantees for MSVC.
Dear Stackoverflow community,
I'm still bit fresh in c++ and I've been scratching my head and haven't found a solution to my problem yet. I've been searching and trying things for a while now and I've gotten to the point where asking a question would be more beneficial and educational.
Problem:
I'd like to make a class or function that wraps/decorates a given function with or without parameters.
Like a good old fashioned #wrapthis in python or c# and the like.
The closest thing I found so far (that is elegant, short and easy to use) is from this stackoverflow answer: C++ Equivalent Decorator
The scratching-my-head part is trying to pass a pointer-function. The error I'm receiving:
Error (active) E0300 a pointer to a bound function may only be used to call the function
Which obviously means that somehow passing a pointer in this fashion is not allowed, so what are my options here?
A working example as answer would be great!
Example of what I'm trying to achieve can be found below:
Something.h
class Something
{
private:
public:
Something() {}
void v_func_with_nothing() { std::cout << "v_func_with_nothing" << "\n"; }
void v_func_with_void(void) { std::cout << "v_func_with_void" << "\n"; }
void v_func_with_one_arg(int x) { std::cout << "v_func_with_one_arg" << x << " " << "\n"; }
void v_func_with_args(int x, int y) { std::cout << "v_func_with_args" << x << " " << y << "\n"; }
int return_func_with_nothing() { return 1; }
int return_func_with_void(void) { return 3; }
int return_func_with_one_arg(int x) { return x; }
int return_func_with_args(int x, int y) { return x+y; }
};
Decorator.h [Again source: C++ Equivalent Decorator]
template<typename T>
auto decorator(T&& func)
{
auto new_function = [func = std::forward<T>(func)](auto&&... args)
{
std::cout << "BEGIN decorating...\n";
auto result = func(std::forward<decltype(args)>(args)...);
std::cout << "END decorating\n";
return result;
};
return new_function;
}
main.cpp
#include <iostream>
#include "Something.h"
#include "Decorator.h"
int main()
{
Something* something = new Something();
auto somedeco = decorator(&something->return_func_with_one_arg);//<-- error here in argument
//int value = somedeco(**enter an argument**);
//std::cout << value << "\n";
return 0;
}
Thank you!
EDIT: SOLUTION
Based on the kind answers given down below I thought of editing this post with an example. The solution to the problem was using lambda.
Decorator.h: I created 2 decorators (one for return-functions, one for void-functions):
template<typename T>
auto DECO_R(T&& func)
{
try
{
auto new_function = [func = std::forward<T>(func)](auto&&... args)
{
std::cout << "BEGIN RETURN decorating...\n";
auto result = func(std::forward<decltype(args)>(args)...);
std::cout << "END RETURN decorating\n";
return result;
};
return new_function;
}
catch (const std::exception& ex)
{
std::cout << ex.what() << "\n";
}
}
template<typename T>
auto DECO_V(T&& func)
{
try
{
auto new_function = [func = std::forward<T>(func)](auto&&... args)
{
std::cout << "BEGIN VOID decorating...\n";
func(std::forward<decltype(args)>(args)...);
std::cout << "END VOID decorating\n";
};
return new_function;
}
catch (const std::exception& ex)
{
std::cout << ex.what() << "\n";
}
}
Main.cpp: 2 examples
int main()
{
Something* something = new Something();
auto somedeco = DECO_R(
[&](int x) {
return something->return_func_with_one_arg(x);
});
int value = somedeco(255);
std::cout << value << "\n";
auto some_v_deco = DECO_V(
[&](int x) {
return something->v_func_with_one_arg(x);
});
some_v_deco(2);
return 0;
}
Output
BEGIN RETURN decorating...
END RETURN decorating
255
BEGIN VOID decorating...
v_func_with_one_arg2
END VOID decorating
I hope this helps others out there.
The call decorator(&something->return_func_with_one_arg) is invalid. There's no such thing as a pointer to a bound function in C++.
If you want somedeco to be a function-like object that wraps a call to something->return_func_with_one_arg(42), for example, you will need to wrap the call either in a lambda:
auto somedeco = decorator(
[&]() {
return something->return_func_with_one_arg(42);
}
);
somedeco();
Or you could pass the parameter through the decorator:
auto somedeco = decorator(
[&](int x) {
return something->return_func_with_one_arg(x);
}
);
somedeco(42);
Keep in mind that this will require that the object pointed to by something outlives the object returned by decorator.
There is no simple 1:1 replacement for Pythons dynamic typing in C++. Your example does not compile, because there are no pointer to member function of one specific instance. Pointer to member functions always need an instance to be called. For one simple case I would suggest to use a lambda:
int main() {
Something something;
auto somedeco = [&](auto param) {
// before call
auto v = something.return_func_with_one_arg(param);
// after call
return v;
};
return somedeco(1);
}
As you can see the whole machinery of decorate isn't really needed, because with a lamdda you can write the wrapped function inline. On the other hand, the decorator allows you to reuse // before call and // after call for different methods. To fix your code you could also pass the lambda to decorate.
PS: Don't use new to create objects.
you need bind it
int main()
{
Something* something = new Something();
using std::placeholders::_1;
auto f = std::bind( &Something::return_func_with_one_arg, something, _1 );
auto somedeco = decorator( f );//<-- error here in argument
//int value = somedeco(**enter an argument**);
//std::cout << value << "\n";
return 0;
}
https://godbolt.org/z/zdYW9q
I'm writing a chess engine, and I have a function that looks like this:
U64 find_moves(Piece type, Team side, uint8_t square, U64 occupied) {
switch (type) {
case PAWN: {
U64 result = 0;
result |= occupied & bb_normal_moves::pawn_caps[side][square];
if (!(occupied & bb_normal_moves::pawn_moves_x1[side][square])) {
result |= bb_normal_moves::pawn_moves_x1[side][square];
if (!(occupied & bb_normal_moves::pawn_moves_x2[side][square])) {
result |= bb_normal_moves::pawn_moves_x2[side][square];
}
}
return result;
}
case KNIGHT:
return bb_normal_moves::knight_moves[square];
case BISHOP:
return bb_magics::bishop_moves(square, occupied);
case ROOK:
return bb_magics::rook_moves(square, occupied);
case QUEEN:
return bb_magics::bishop_moves(square, occupied) | bb_magics::rook_moves(square, occupied);
case KING:
return bb_normal_moves::king_moves[square];
}
return 0; // Can't happen
}
It essentially delegates to another function call depending on the type parameter. In many places around the program, this function is called after looping through different Piece values, which happens to be an enum.
Unfortunately, that means that this function is called each time in that loop, so a lot of CPU time is wasted in this function branching.
What I'd like to do is change this function to allow the compiler to optimise the calls:
template <Piece type> U64 find_moves(Team side, uint8_t square, U64 occupied)
but then my loops would not compile as the target of the function call cannot be resolved at compile time.
Is there a way of optimising this function without manually unrolling all of my loops?
EDIT: Here is an example of one of the loops that calls find_moves:
for (uint8_t piece = 1; piece < 6; piece++) {
move.info.piece = piece;
U64 bb_piece = board.bb_pieces[team][piece];
while (bb_piece) {
uint8_t from = pop_bit(team, bb_piece);
move.info.from = from;
U64 bb_targets = find_moves((Piece) piece, team, from, board.bb_all) & mask;
while (bb_targets) {
uint8_t to = pop_bit(x_team, bb_targets);
move.info.to = to;
buf[buf_size++] = move;
}
}
}
Given that the values of your Piece enum are from 1 to 6, you can use templates, std::make_index_sequence, std::index_sequence to unroll.
Sorry but I can only prepare a minimal example (no move, no board, etc).
If you call something as
foo(std::make_index_sequence<6U>{});
in foo() you can call another function with singles values (you tagged C++17 so you can use template folding)
template <std::size_t ... Ps>
void foo (std::index_sequence<Ps...> const &)
{ (bar<Ps>(), ...); }
My idea is that in bar() you can place the content of the body of the for (uint8_t piece = 1; piece < 6; piece++) loop of your example; I place only the call to a trivial (no other arguments) find_moves() function.
template <std::size_t Ps>
void bar ()
{ find_moves<pieces(1+Ps)>(); }
Now you can develop six find_moves() template function using full specialization (I write only std::cout messages; you, using other arguments, can place the content of the cases in your switch.
template <pieces P>
void find_moves ();
template <>
void find_moves<Pawn> ()
{ std::cout << "Case Pawn" << std::endl; }
template <>
void find_moves<Knight> ()
{ std::cout << "Case Knight" << std::endl; }
template <>
void find_moves<Bishop> ()
{ std::cout << "Case Bishop" << std::endl; }
template <>
void find_moves<Rook> ()
{ std::cout << "Case Rook" << std::endl; }
template <>
void find_moves<Queen> ()
{ std::cout << "Case Queen" << std::endl; }
template <>
void find_moves<King> ()
{ std::cout << "Case King" << std::endl; }
The following is a full compiling example
#include <iostream>
#include <utility>
#include <type_traits>
enum pieces { Pawn = 1, Knight, Bishop, Rook, Queen, King };
template <pieces P>
void find_moves ();
template <>
void find_moves<Pawn> ()
{ std::cout << "Case Pawn" << std::endl; }
template <>
void find_moves<Knight> ()
{ std::cout << "Case Knight" << std::endl; }
template <>
void find_moves<Bishop> ()
{ std::cout << "Case Bishop" << std::endl; }
template <>
void find_moves<Rook> ()
{ std::cout << "Case Rook" << std::endl; }
template <>
void find_moves<Queen> ()
{ std::cout << "Case Queen" << std::endl; }
template <>
void find_moves<King> ()
{ std::cout << "Case King" << std::endl; }
template <std::size_t Ps>
void bar ()
{ find_moves<pieces(1+Ps)>(); }
template <std::size_t ... Ps>
void foo (std::index_sequence<Ps...> const &)
{ (bar<Ps>(), ...); }
int main ()
{
foo(std::make_index_sequence<6U>{});
}