C++ Variadic Delegates - c++

I am trying to make a Variadic Delegate structure while trying to grasp templates and variadic template arguments. I came up with the following:
template <typename T, typename R, typename... Parameters>
class Delegate
{
private:
T& object;
R (T::*method)(Parameters...);
public:
Delegate(T& object, R(T::*method)(Parameters...))
: object(object), method(method)
{}
R Call(Parameters...)
{
return (object.*method)(Parameters...);
}
};
and my main function looks like this:
class A
{
public:
int F(int a)
{
return a * x;
}
int x;
};
int main()
{
A a;
a.x = 5;
Delegate<A, int, int> d(a, &A::F);
d.Call(8);
return 0;
}
But that gives me the following errors:
error C2144: syntax error : 'int' should be preceded by ')'
while compiling class template member function 'int Swift::Utility::Delegate<A,int,int>::Call(int)'
error C2198: 'int (__thiscall A::* )(int)' : too few arguments for call
error C2059: syntax error : ')'
I tried some different ways on calling the member functions but I can't get it to work...
Also if you can show me a different alternative that provides the same basic functionality I would also be happy!

You're not providing actual arguments, only their types:
R Call(Parameters... params)
{
return (object.*method)(params...);
}
is probably what you were looking for (or close to it).

Related

Taking Eigen::Vector as a parameter

I am trying to write a function that takes an Eigen::Vector<T, dim> as a parameter. However, the following example fails to compile:
#include <Eigen/Core>
template<class F, typename T, int dim>
void bar(F&& func, const Eigen::Vector<T, dim>& arg1) {
}
template<typename T, int dim>
void foo(const Eigen::Vector<T, dim>& a) {
return bar([] {}, a);
}
int main() {
Eigen::Vector<float, 3> v1{ 1.f,2.f,3.f };
foo(v1);
return 0;
}
This, under Visual Studio 2019, gives me the following error:
1>main.cpp(9,10): error C2672: 'bar': no matching overloaded function found
1>main.cpp(14): message : see reference to function template instantiation 'void foo<float,3>(const Eigen::Matrix<float,3,1,0,3,1> &)' being compiled
1>main.cpp(9,1): error C2784: 'void bar(F &&,const Eigen::Matrix<T,dim,1,|_Rows==&&?:&&_Rows!=?:,_Rows,1> &)': could not deduce template argument for 'const Eigen::Matrix<T,dim,1,|_Rows==&&?:&&_Rows!=?:,_Rows,1> &' from 'const Eigen::Matrix<float,3,1,0,3,1>'
1>main.cpp(4): message : see declaration of 'bar'
My questions:
What is this weird |_Rows==&&?:&&_Rows!=?: in the error message?
What can I do to make the above code compile?
The bar function should have T and dim availabe. I cannot just take const AnyType& arg1, because the actual implementation of bar depends on compile-time known values T and dim.
I have seen https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html. I think I understand what they are saying, but I am not sure if it applies here. I am taking an actual Eigen::Vector as an argument, not an expression.
If there was an expression it would be fine for me, to have it materialized.
Nevertheless, if I try to follow their instruction and just use ArrayBase<Derived>, I lose the compile-time information about T and dim.
This indeed looks like an MSVC issue, it compiles fine with gcc >= 4.7, and clang >= 3.5: https://godbolt.org/z/kqoHyO
One possible workaround would be to explicitly write out what Eigen::Vector expands to:
template<class F, typename T, int dim>
void bar(F&& func, const Eigen::Matrix<T, dim, 1, 0, dim, 1>& arg1) {
}
https://godbolt.org/z/vlvSDP
The weird |_Rows==&&?:&&_Rows!=?: looks like MSVC mangled the default value of the Options template parameter:
AutoAlign |
( (_Rows==1 && _Cols!=1) ? Eigen::RowMajor
: (_Cols==1 && _Rows!=1) ? Eigen::ColMajor
: EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION ),
If you want to get to the bottom of this, you should file a bug-report to the MSVC maintainers, maybe using a simplified example like this: https://godbolt.org/z/U_0Sh7 (probably it's possible to reduce this even more).

Simple parameter pack expansion: expected ';'

In the following snippet:
void normalize(path& p)
{
// do something with p
}
template<typename... T>
void normalize(T&... t)
{
normalize(t)...; // (L)
}
In my actual understanding, the line (L) expands to:
template<typename... T>
void normalize(T&... t) // T = {t1, t2, t3}, for example
{
normalize(t1), normalize(t2), normalize(t3);
}
and each one of these expressions will execute the one-parameter version of normalize. However, g++ (4.8.1) throws me the following error:
prueba.cpp: In function 'void normalize(T& ...)':
prueba.cpp:155:17: error: expected ';' before '...' token
normalize(t)...;
^
prueba.cpp:155:20: error: parameter packs not expanded with '...':
normalize(t)...;
^
prueba.cpp:155:20: note: 't'
What's wrong with my code?
The expansion of parameter packs is not allowed in this context. If you create a helper class pass, you can do the following:
pass{(normalize(std::forward<T>(t)), 0)...};
The helper class pass might look as follows:
struct pass
{
template <typename ...Args>
explicit pass(Args&&...) { }
};
I think you would want to unpack your parameter pack into a function call site or tuple, like this:
make_tuple(normalize(t)...); // (L)
For example, the following code would compile under gcc-4.8.1:
#include <tuple>
using namespace std;
typedef int path;
void normalize(path& p)
{
// do something with p
}
template<typename... T>
void normalize(T&... t)
{
auto tp = make_tuple(normalize(t)...); // (L)
//do whatever you want with the components of tp ...
}
main() {}

C++ typedef function definition as a class member to use later for function pointer?

I need to have a class that stores a function definition/prototype as a class member in order to use it later to get function pointers based on that definition.
#include <cstdlib>
#include <cstdio>
#include <functional>
template<typename... Ts>
class Function;
template <typename R>
class Function<R>
{
public:
using FuncType = R (*) ();
Function()
{
printf("R()\n");
}
};
template <typename R, typename... A>
class Function<R, A...>
{
public:
using FuncType = R (*) (A...);
Function()
{
printf("R(A)\n");
}
};
void fn1(int i) { printf("Called fn1: %d\n", i); }
void fn2(int i, float f) { printf("Called fn2: %d, %f\n", i, f); }
void fn3() { printf("Called fn3: N/A \n"); }
int main(int argc, char **argv)
{
Function<void, int> myFuncX;
Function<void, int, float> myFuncY;
Function<void> myFuncZ;
myFuncX.FuncType mf1 = fn1;
myFuncY.FuncType mf2 = fn2;
myFuncZ.FuncType mf3 = fn3;
fn1(244);
fn2(568, 1.891);
fn3();
return EXIT_SUCCESS;
}
Objects are unknown until runtime which is the reason I need them to be class members. They're stored in an std::map and I need to be able to get a specific item from the map and to use it's function definition/prototype to store the pointer of a function.
But I always get this kind of error:
||=== Build: Win32 Release in Sandbox (compiler: GNU GCC Compiler) ===
.\src\testdummy.cpp||In function 'int main(int, char**)':
.\src\testdummy.cpp|42|error: invalid use of 'using FuncType = void (*)(int)'
.\src\testdummy.cpp|42|error: expected ';' before 'mf1'
.\src\testdummy.cpp|43|error: invalid use of 'using FuncType = void (*)(int, float)'
.\src\testdummy.cpp|43|error: expected ';' before 'mf2'
.\src\testdummy.cpp|44|error: invalid use of 'using FuncType = void (*)()'
.\src\testdummy.cpp|44|error: expected ';' before 'mf3'
||=== Build failed: 6 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===
I've tried with std::function, typedef etc. Why do I get this?
This is wrong:
myFuncX.FuncType mf1 = fn1;
You can't use a type alias as a normal member - it's a declaration inside class' scope, similar as typedefs. This will work:
decltype(myFuncX)::FuncType mf1 = fn1;

Error when inheriting from templated class and calling templated function

I've got some template code that I'm modifying and I've run into an odd error that I can't work around. I was able to recreate the problem with the below simpler (but admittedly pointless) code snippet:
struct Widget
{
};
template <typename A>
class Foo
{
public:
template <int numA>
inline bool funcCall()
{
return numA > 0;
}
inline bool funcCallNoTemplate()
{
return false;
}
};
template <typename B>
class Bar : public Foo<B>
{
public:
// doesn't work
bool concrete()
{
return Foo<B>::funcCall<5>();
}
// works fine
bool other()
{
return Foo<B>::funcCallNoTemplate();
}
};
int main()
{
Bar<Widget> b;
b.concrete();
b.other();
return 0;
}
The error I get with GCC 4.7 is the following (line 30 is the body of Bar::concrete):
example.cxx: In member function ‘bool Bar<B>::concrete()’:
example.cxx:30: error: expected primary-expression before ‘)’ token
example.cxx: In member function ‘bool Bar<B>::concrete() [with B = Widget]’:
example.cxx:43: instantiated from here
example.cxx:30: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
It seems like the compiler can't even parse this correctly, am I missing something here that makes that line completely bogus?
It seems like the compiler can't even parse this correctly, am I missing something here that makes that line completely bogus?
Yes. You need to use the template disambiguator:
return Foo<B>::template funcCall<5>();
// ^^^^^^^^
This way you will tell the compiler to parse the dependent name funcCall as the name of a member function template, and the subsequent angular brackets as delimiters for the corresponding template arguments.
Without it, funcCall will be parsed as the name of a data member, while < and > will be parsed as less-than and greater-than, respectively.

Is the code in "The C++ Programming Language Third Edition" on page 854 correct?

I try to learn C++. In "The C++ Programming Language Third Edition" book I found code on page 854 (Appendix C.13.1):
template<class T> class X {
static T def_val;
static T* new_X(T a = def_val);
};
template<class T> T X<T>::def_val(0, 0);
template<class T> T* X<T>::new_X(T a) { /* ... */ }
template<> int X<int>::def_val<int> = 0;
template<> int* X<int>::new_X<int>(int i) { /* ... */ }
I modify it:
template<class T> class X {
static T def_val;
static T* new_X(T a = def_val);
};
template<class T> T X<T>::def_val(0, 0);
template<class T> T* X<T>::new_X(T a) { return new T(a); }
template<> int X<int>::def_val<int> = 0;
template<> int* X<int>::new_X<int>(int i) { return new int(i); }
But my compiler won't compile it:
1>main.cpp(15): error C2143: syntax error : missing ';' before '<'
1>main.cpp(15): error C2988: unrecognizable template declaration/definition
1>main.cpp(15): error C2059: syntax error : '<'
1>main.cpp(16): error C2143: syntax error : missing ';' before '<'
1>main.cpp(16): error C2470: 'X<T>::new_X' : looks like a function definition, but there is no parameter list; skipping apparent body
1> with
1> [
1> T=int
1> ]
1>main.cpp(16): error C2988: unrecognizable template declaration/definition
1>main.cpp(16): error C2059: syntax error : '<'
1>main.cpp(19): error C2143: syntax error : missing ';' before '{'
1>main.cpp(19): error C2447: '{' : missing function header (old-style formal list?)
1>
1>Build FAILED.
What wrong code in the book or compiler?
The code from the book is wrong. The last two lines should read:
template<> int X<int>::def_val = 0;
template<> int* X<int>::new_X(int i) { return new int(i); }
Don't forget to mail Stroustrup. From his homepage:
"As a small token of my gratitude to
people who report problems and thereby
help me improve the book, I offer a
reward to someone who first reports a
misspelling, a bug in a code example,
or a factual error in the text to me.
The bounty for new errors in the text
is US$32."
Edit: Oops. You are too late. The bug was fixed in the 19th printing. See here. So no bounty, sorry!
The corrected version looks like this:
template class X {
// ...
static T def_val;
static T* new_X(T a = def_val);
};
template< class T> T X<T>::def_val; // initialize to X<T>()
template< class T> T* X<T>::new_X(T a) { /* ... */ }
template< > int X<int>::def_val = 0;
template< > int* X<int>::new_X(int i) { /* ... */ }
You want
template<class T> class X {
static T def_val;
static T* new_X(T a = def_val);
};
template<class T> T X<T>::def_val(0, 0);
template<class T> T* X<T>::new_X(T a) { return new T(a); }
template<> int X<int>::def_val = 0;
template<> int* X<int>::new_X(int i) { return new int(i); }