C++ Build error: expected type-specifier before [Variadic templates] class - c++14

Here is my code:
#include <stdio.h>
#include <utility>
#include <tuple>
template <typename Obj, typename Method, typename Args, size_t... Ns>
inline void DispatchToMethodImpl(const Obj& obj, Method method, Args&& args,
std::index_sequence<Ns...>) {
(obj->*method)(std::get<Ns>(std::forward<Args>(args))...);
}
template <typename Obj, typename Method, typename Args>
inline void DispatchToMethod(const Obj& obj, Method method, Args&& args) {
constexpr size_t size = std::tuple_size<std::decay_t<Args>>::value;
DispatchToMethodImpl(obj, method, std::forward<Args>(args),
std::make_index_sequence<size>());
}
class TaskEventBase {
public:
virtual void Run() = 0;
};
template <typename Obj, typename Method, typename Args>
class TaskEvent : public TaskEventBase {
public:
TaskEvent(Obj* obj, Method method, Args&& args) {
obj_ = obj;
method_ = method;
args_ = std::forward<Args>(args);
}
void Run() override { DispatchToMethod(obj_, method_, args_); }
private:
Obj* obj_;
Method method_;
Args args_;
};
int main() {
printf("event loop test start\n");
struct Foo {
int x;
int y;
int Add(int a, int b) {
printf("res is %d\n", a + b);
return a + b;
}
};
Foo foo;
DispatchToMethod(&foo, &Foo::Add, std::make_tuple(1, 2));
auto e = new TaskEvent(&foo, &Foo::Add, std::make_tuple(1, 2));
printf("event loop test end\n");
return 0;
}
Try build with:
g++ -g -Wall -std=c++14 -o a test_template_args.cc
Then I get the following error:
test_template_args.cc:70:16: error: expected type-specifier before ‘TaskEvent’
auto e = new TaskEvent(&foo, &Foo::Add, std::make_tuple(1, 2));
I don't understand why DispatchToMethod function template works:
DispatchToMethod(&foo, &Foo::Add, std::make_tuple(1, 2));
But TaskEvent class template doesn't work:
auto e = new TaskEvent(&foo, &Foo::Add, std::make_tuple(1, 2));

Since C++17 your code works due to CTAD.
Until C++14, the code doesn't work because constructor of TaskEvent is non template function, so class template parameters cannot be deduced from the call parameters of TaskEvent constructor, contrary to DispatchToMethod which is template function - all Obj, Method and Args are deducible from passed arguments of function invocation.
You can explicitly provide template parameters via template arguments list:
auto e = new TaskEvent< Foo,int(Foo::*)(int,int),std::tuple<int,int> >
(&foo, &Foo::Add, std::make_tuple(1, 2));

Related

Error with lambda in template member function

I have the following c++ code
#include <iostream>
template<typename Func>
class Foo
{
private:
Func func;
public:
Foo(Func func) : func(func) {}
template<typename T>
Func wrap()
{
Func clbk = func;
auto wrapperCB = [clbk](T t) {
auto job = [clbk, t](){
clbk(t);
};
job();
};
return wrapperCB;
}
template<typename T>
void call(T t)
{
func(t);
}
};
int main()
{
int m = 2;
auto f = [](int & p) {std::cout << "test success " << p << "\n";};
auto obj = std::make_shared<Foo<std::function<void(int &)>>>(f);
auto wrapper = obj->template wrap<int &>();
wrapper(m);
return 0;
}
This is giving compilation error
tsavs-mbp:p utsagarw$ clear; g++ -std=c++11 a.cpp -o z; ./z
a.cpp:18:17: error: no matching function for call to object of type 'const std::__1::function<void (int &)>'
clbk(t);
^~~~
a.cpp:38:32: note: in instantiation of function template specialization 'Foo<std::__1::function<void (int &)> >::wrap<int &>' requested here
auto wrapper = obj->template wrap<int &>();
^
/Applications/Xcode_10.1/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1677:9: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
_Rp operator()(_ArgTypes...) const;
^
1 error generated.
I don't understand this error. Where did this const come from?
It is building successfully if in wrap I don't create job functor and call clbk directly. What is this job doing to type T?
template<typename T>
Func wrap()
{
Func clbk = func;
auto wrapperCB = [clbk](T t) {
clbk(t);
};
return wrapperCB;
}
If you want to modify any captured variable inside lambda you have to specify it as mutable.
t variable is captured by copy, so you can only read it:
auto job = [clbk, t]() // <-- t passed by copy
{
clbk(t); // clbk takes t by reference -> int&
};
your callback, clbk has signature int& so it means it could modify t. What is not allowed.
Solution:
auto job = [clbk, t]() mutable // keyword 'mutable' added
{
clbk(t); // clbk can change t
};
or make function taking const int& as parameter - then t can be only read.
Demo

Template function taking generic pointer to member function with both const& and by-value implementations

I want to have a template function which accepts unary member-function pointers of an instance of some generic type.
My problem is that I must support both void(T val) and void(const T& val) member functions.
I have written one template function for each case and it works fine, but this leads to code duplication since the function logic is completely the same. (I found something completely similar here: Function taking both pointer to member-function and pointer to const member-function but I fail to see a definitive solution).
An example of the generic type mentioned above:
using UserAddress = std::string;
class User
{
private:
int mHeight;
UserAddress mAddress;
public:
void SetHeight(int height){mHeight = height;}
void SetAddress(const UserAddress& address){mAddress = address;}
};
Where UserAddress is some heavy type I want to pass by reference.
My templated function:
template <typename TPersistentObject>
class Persistence
{
private:
std::map<std::string, std::function<void(User*)>> mSetterOfProperty;
template <typename TPersistentObject, typename TPropertyValue>
void DefinePropertySettingMethod(const std::string& propertyName,
void (TPersistentObject::*propertySetter)(TPropertyValue), std::function<TPropertyValue(void)> dataReader)
{
mSetterOfProperty[propertyName] =
[propertySetter, columnDataReader](TPersistentObject* persistentObject)
{
(persistentObject->*propertySetter)(dataReader());
};
}
};
/// Const& implementation leading to code duplication
template <typename TPersistentObject, typename TPropertyValue>
void DefinePropertySettingMethod(const std::string& propertyName,
void (TPersistentObject::*propertySetter)(const TPropertyValue&), std::function<TPropertyValue(void)> dataReader)
{
...
}
};
Is there some way to define this function to support the following:
int main()
{
auto intDataReader = []() {
return 1;
};
auto stringDataReader = []() {
return UserAddress("Next Door");
};
Persistence p;
p.DefinePropertySettingMethod<User,int>("Height", &User::SetHeight, intDataReader);
p.DefinePropertySettingMethod<User,UserAddress>("Address", &User::SetAddress, stringDataReader);
}
Thanks to Igor Tandetnik 's tip I managed to compile a solution. std::enable_if is not what I needed though since I did not need to deactivate an overload (or at least I couldn't come to a solution using it).
std::conditional did the trick.
Here is the code:
#include <string>
#include <functional>
#include <map>
#include <string>
#include <type_traits>
using UserAddress = std::string;
class User
{
private:
int mHeight;
UserAddress mAddress;
public:
void SetHeight(int height){mHeight = height;}
void SetAddress(const UserAddress& address){mAddress = address;}
};
template <typename TPersistentObject>
class Persistence
{
public:
std::map<std::string, std::function<void(TPersistentObject*)>> mSetterOfProperty;
template <typename TPropertyValue>
void DefinePropertySettingMethod(const std::string& propertyName,
void (TPersistentObject::*propertySetter)(TPropertyValue),
std::function<
typename std::conditional<!std::is_same<TPropertyValue, typename std::decay<TPropertyValue>::type>::value,
typename std::decay<TPropertyValue>::type, TPropertyValue>::type
(void)> dataReader)
{
mSetterOfProperty[propertyName] =
[propertySetter, dataReader](TPersistentObject* persistentObject)
{
(persistentObject->*propertySetter)(dataReader());
};
}
};
int main()
{
std::function<int()> intDataReader = []() {
return 1;
};
std::function<std::string()> stringDataReader = []() {
return UserAddress("Next Door");
};
Persistence<User> p;
p.DefinePropertySettingMethod("Height", &User::SetHeight, intDataReader);
p.DefinePropertySettingMethod("Address", &User::SetAddress, stringDataReader);
}

Type mismatch of pointer to template member function

I am following this code snippet which makes it easier to pass a member function to an interface expecting a C-style callback (that is, the interface expects a function pointer to the callback, and a void* pointer to user data which will in turn be passed to the callback). Effectively I want to convert Helper::M to Helper::V below.
I am trying to modify the snippet to automatically deduce the template parameters. Here is my current attempt.
#include <iostream>
template <typename R, typename T, typename... Args>
struct Helper {
using V = R (*)(void*, Args...);
using M = R (T::*)(Args...);
template <M m>
static R Fn(void* data, Args... args) {
return (static_cast<T*>(data)->*m)(std::forward<Args...>(args...));
}
};
template <typename R, typename T, typename... Args>
typename Helper<R, T, Args...>::V Cast(R (T::*m)(Args...)) {
return Helper<R, T, Args...>::template Fn<m>;
}
int CIntf(void* data, int (*f)(void*, int)) { return f(data, 1); }
struct UserData {
int x;
int Add(int y) { return x + y; }
};
int main(int argv, char** argc) {
UserData data = {4};
// Explicit parameters; works.
std::cout << CIntf(&data, Helper<int, UserData, int>::Fn<&UserData::Add>)
<< "\n";
// Deduced parameters; fails.
std::cout << CIntf(&data, Cast(&UserData::Add)) << "\n";
return 0;
}
I tried to compile with gcc -std=c++11 -lstdc++. The explicit parameters method works fine, but the deduced parameters method gives the following error:
tmp.cc: In instantiation of ‘typename Helper<R, T, Args>::V Cast(R (T::*)(Args ...)) [with R = int; T = UserData; Args = {int}; typename Helper<R, T, Args>::V = int (*)(void*, int)]’:
tmp.cc:30:58: required from here
tmp.cc:15:42: error: no matches converting function ‘Fn’ to type ‘using V = int (*)(void*, int) {aka int (*)(void*, int)}’
return Helper<R, T, Args...>::template Fn<m>;
^~~~~
tmp.cc:8:12: note: candidate is: template<int (UserData::* m)(int)> static R Helper<R, T, Args>::Fn(void*, Args ...) [with R (T::* m)(Args ...) = m; R = int; T = UserData; Args = {int}]
static R Fn(void* data, Args... args) {
Note that it correctly deduced the template parameters, but failed to convert Helper<int, UserData, int>::Fn<m> to int (*)(void*, int); why? This same conversion succeeded in the explicit case (unless m is somehow different from &UserData::Add).
Unfortunately you'll have to use a macro for this:
#define makeFunc(method) &Helper<decltype(method)>::Fn<method>
And redefine your helper like this for it to work:
template <typename T>
struct Helper;
template <typename R, typename T, typename... Args>
struct Helper<R(T::*)(Args...)>
The reason why you can't use deduction for this, is that deduction only works on function arguments which are run-time values. And you need to use a method's address as template argument which should be a compile-time value.
So when you do this:
return Helper<R, T, Args...>::template Fn<m>;
you are passing a run-time value m as a template argument which is impossible.
For reference, here is the complete code using the macro. Also note the use of std::forward in the original code was incorrect for multiple arguments (see this answer).
#include <iostream>
#include <utility>
template <typename T>
struct Helper;
template <typename R, typename T, typename... Args>
struct Helper<R (T::*)(Args...)> {
template <R (T::*m)(Args...)>
static R Fn(void* t, Args... args) {
return (static_cast<T*>(t)->*m)(std::forward<Args>(args)...);
}
};
#define VOID_CAST(m) &Helper<decltype(m)>::Fn<m>
struct UserData {
int x;
int Add1(int y) { return x + y; }
int Add2(int y, int z) { return x + y + z; }
};
int Call1(void* data, int (*f)(void*, int)) { return (*f)(data, 1); }
int Call2(void* data, int (*f)(void*, int, int)) { return (*f)(data, 1, 2); }
int main() {
UserData data = {4};
std::cout << Call1(&data, VOID_CAST(&UserData::Add1)) << "\n";
std::cout << Call2(&data, VOID_CAST(&UserData::Add2)) << "\n";
return 0;
}

c++11 segmentation fault while playing with variadic templates

So I was Playing around with c++11 Varidiacs, and I wanted to create a thing called CallClass, basically a class that warps a function, for later call,when all variables are set(truly I have No Idea If It can Be Useful):
#include <tuple>
template <typename OBJ,typename F,typename... VARGS>
class CallClass
{
public:
CallClass(OBJ& object,F callFunction)
:_object(&object),_func(callFunction)
{ }
CallClass(const CallClass& other)
:_func_args(other._func_args)
,_object(other._object)
,_func(other._func)
{ }
template <size_t INDEX>
auto get(){ return std::get<INDEX>(_func_args); }
template <size_t INDEX,typename T>
void set(const T& val){ std::get<INDEX>(_func_args) = val; }
template <size_t INDEX,typename T>
void set(T&& val){ std::get<INDEX>(_func_args) = val; }
auto Call()
{
//throws segmentation Fault Here
return InnerCall<0>(_func_args);
}
virtual ~CallClass() {}
protected:
private:
std::tuple<VARGS...> _func_args;
OBJ* _object;
F _func;
template <size_t INDEX,typename... ARGS>
auto InnerCall(std::tuple<VARGS...>& tup,ARGS... args)
{
auto arg = std::get<INDEX>(tup);
return InnerCall<INDEX + 1>(tup,args...,arg);
}
template <size_t INDEX,VARGS...>
auto InnerCall(std::tuple<VARGS...>& tup,VARGS... args)
{
return (_object->*_func)(args...);
}
};
Now when I try to compile(compiling using IDE:code::blocks, configured to use MINGW On windows ), it prints Compiler:Segmentation Fault, anybody any Ideas?
Usage:
class obj{
public:
obj(int a)
:_a(a)
{ }
virtual ~obj() {}
int add(int b,int c){
return _a + b + c;
}
private:
int _a;
};
int main(){
obj ob(6);
CallClass<obj,decltype(obj::add),int,int> callAdd(ob,obj::add);
callAdd.set<0,int>(5);
callAdd.set<1,int>(7);
cout << "result is " << callAdd.Call() << endl;
return 0;
}
After a Bit of a search i stumbled upon a similar issue, in a way.
apparently the way I'm unpacking the tuple is an issue, so i decided to use a different approach as shown in: enter link description here
had to add a few changes to suit my needs:
changes:
namespace detail
{
template <typename OBJ,typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl
{
static auto call(OBJ& obj,F f, Tuple && t)
{
return call_impl<OBJ,F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(obj,f, std::forward<Tuple>(t));
}
};
template <typename OBJ,typename F, typename Tuple, int Total, int... N>
struct call_impl<OBJ,F, Tuple, true, Total, N...>
{
static auto call(OBJ& obj,F f, Tuple && t)
{
return (obj.*f)(std::get<N>(std::forward<Tuple>(t))...);
}
};
}
// user invokes this
template <typename OBJ,typename F, typename Tuple>
auto call(OBJ& obj,F f, Tuple && t)
{
typedef typename std::decay<Tuple>::type ttype;
return detail::call_impl<OBJ,F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(obj,f, std::forward<Tuple>(t));
}
and changed Call():
auto Call()
{
std::tuple<VARGS...> func_args = _func_args;
return call(*_object,_func, std::move(func_args));
}
I will probably make a few more changes, like passing the tuple as a reference, and making the structs a part of my class.

How to determine number of function arguments dynamically

I have the following code:
#include <iostream>
#include <functional>
class test
{
public:
typedef std::function<bool(int)> Handler;
void handler(Handler h){h(5);}
};
class test2
{
public:
template< typename Ret2, typename Ret, typename Class, typename Param>
inline Ret2 MemFn(Ret (Class::*f)(Param), int arg_num)
{
if (arg_num == 1)
return std::bind(f, this, std::placeholders::_1);
}
bool f(int x){ std::cout << x << std::endl; return true;}
};
int main()
{
test t;
test2 t2;
t.handler(t2.MemFn<test::Handler>(&test2::f, 1));
return 0;
}
It works as expected.
I would like to be able to call this:
t.handler(t2.MemFn<test::Handler>(&test2::f));
instead of
t.handler(t2.MemFn<test::Handler>(&test2::f, 1));
Basically I need MemFn to determine in runtime what Handler expects as the number of arguments.
Is that even possible?
You may create some type_traits to have your info, something like:
template <typename T> struct function_trait;
template <typename Ret, typename ... Args>
struct function_trait<std::function<Ret(Args...)>>
{
static constexpr std::size_t args_count = sizeof...(Args);
};
And so your method may look like:
template<typename Ret2, typename Ret, typename Class, typename Param>
inline Ret2 MemFn(Ret (Class::*f)(Param))
{
if (function_trait<Ret2>::args_count == 1)
return std::bind(f, this, std::placeholders::_1);
throw std::runtime_error("invalid number of arguments");
}

Resources