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
)