I have a method that takes an index-able object as a template parameter, something like:
template <typename OBJ>
int foo(int n, OBJ o)
{
int x = 0;
for (int i = 0; i < n; ++i) {
x += o[i];
}
return x;
}
Is there a way I can pass a lambda function in for the o parameter? In other words, having the lambda be call-able via the [] operator rather than the () operator?
template<class F>
struct square_bracket_invoke_t {
F f;
template<class T>
auto operator[](T&& t)const
-> typename std::result_of< F const&(T&&) >::type
{ return f(std::forward<T>(t)); }
};
template<class F>
square_bracket_invoke_t< typename std::decay<F>::type >
make_square_bracket_invoke( F&& f ) {
return {std::forward<F>(f)};
}
Live example.
Code is C++11 and has basically zero overhead.
int main() {
std::cout << foo( 6, make_square_bracket_invoke([](int x){ return x; } ) ) << "\n";
}
result is 0+1+2+3+4+5 aka 15.
Is this a good idea? Maybe. But why stop there?
For max amusement:
const auto idx_is = make_square_bracket_invoke([](auto&&f){return make_square_bracket_invoke(decltype(f)(f));});
int main() {
std::cout << foo( 6, idx_is[[](int x){ return x; }] ) << "\n";
}
You can do that by:
Creating a class template, a functor, that has the operator[] defined.
Implementing the operator[] in terms of the operator() of a std::function.
Storing the lambda in a wrapped std::function as a member variable of the class template.
Here's a demonstrative program.
#include <iostream>
#include <functional>
template <typename OBJ>
int foo(int n, OBJ o)
{
int x = 0;
for (int i = 0; i < n; ++i) {
x += o[i];
}
return x;
}
template <typename> struct Functor;
template <typename R> struct Functor<R(int)>
{
using ftype = std::function<R(int)>;
Functor(ftype f) : f_(f) {}
R operator[](int i) const { return f_(i); }
ftype f_;
};
int main()
{
Functor<int(int)> f = {[](int i) -> int {return i*i;}};
std::cout << foo(10, f) << std::endl;
}
and its output
285
Live demo
PS
Functor is not the appropriate name here. It does not overload the function call operator. I suspect there is a more appropriate name.
Well, if it helps, here's a way to forward a wrapper class's operator[] to your lambda's operator().
template<class F>
struct SubscriptWrapper_t {
F f_;
template<class T> auto operator[](T const& t_) const -> decltype(f_(t_)) {
return f_(t_);
}
};
template<class F>
SubscriptWrapper_t<typename std::decay<F>::type> SubscriptWrapper(F&& f_) {
return{std::forward<F>(f_)};
}
I use wrappers like this a lot. They're convenient, and they don't seem to have any computational overhead, at least when compiled by GCC. You can make one for at or even make one for find.
EDIT: Updated for C++11 (and updated to be able to return a reference)
A sketch of a wrapper type that would do this.
template<typename UnaryFunction>
class index_wrapper
{
public:
index_wrapper(UnaryFunction func) : func(std::move(func)) {}
template<typename T>
std::invoke_result_t<UnaryFunction, T> operator[](T&& t)
{ return func(std::forward<T>(t)); }
private:
UnaryFunction func;
};
With usage
#include <iostream>
template <typename OBJ>
int foo(int n, OBJ o)
{
int x = 0;
for (int i = 0; i < n; ++i) {
x += o[i];
}
return x;
}
int main()
{
index_wrapper f([](int i) -> int { return i*i; });
std::cout << foo(10, f) << std::endl;
}
You might want to restrict it to a single parameter type, so that you can provide member type aliases similar to std::vector::reference et.al.
Related
I am trying to implement Matrix Addition using expression templates. I am facing some trouble. Here is my matrix code:
#include<iostream>
#include<vector>
#include<cassert>
template <typename T>
class MatrixExpression {
public:
double operator[](size_t i) const { return static_cast<T const&>(*this)[i];}
size_t size()const { return static_cast<T const&>(*this).size(); }
};
template<typename T>
class Matrix:public MatrixExpression<Matrix<T>>
{
std::vector<std::vector<T>> mat;
public:
Matrix(std::size_t m, std::size_t n):mat(m,std::vector<T>(n)){}
class Proxy
{
std::vector<T> vec;
public:
Proxy(std::vector<T> vec):vec(vec){ }
T operator[](std::size_t i){ return vec[i];}
//T &operator[](std::size_t i){ return vec[i];}
std::size_t size() const{ return vec.size(); }
};
Proxy operator[](std::size_t i) const { return Proxy(mat[i]); }
//Proxy &operator[](std::size_t i) { return Proxy(mat[i]); }
size_t size() const { return mat.size(); }
Matrix(std::initializer_list<std::initializer_list<T>> lst)
{
int m=0,n=0;
for(auto l:lst )
{
for(auto v:l)
{
n++;
}
m++;
}
int i=0,j=0;
mat(m,std::vector<T>(n));
for(auto l:lst )
{
for(auto v:l)
{
mat[i].push_back(v);
}
i++;
}
}
Matrix(MatrixExpression<T> const& matx):mat(matx.size(),std::vector<T>(matx[0].size))
{
for(int i=0;i<matx.size();i++)
{
for(int j=0;j<matx[0].size();j++)
{
mat[i][j] = matx[i][j];
}
}
}
};
template<typename T, typename X, typename Y>
class MatrixSum:public MatrixExpression<MatrixSum<T,X,Y>>
{
X const& x;
Y const& y;
public:
MatrixSum(X const& x1, Y const& y1):x(x1),y(y1){
assert(x1.size()==y1.size());
assert(x1[0].size()==y1[0].size());
}
class ProxySum
{
std::vector<T> vec1,vec2;
public:
ProxySum(std::vector<T> vec1,std::vector<T> vec2):vec1(vec1),vec2(vec2){ }
T operator[](std::size_t i){ return vec1[i] + vec2[i];}
//T &operator[](std::size_t i){ return vec1[i] + vec2[i];}
std::size_t size() const{ return vec1[0].size(); }
};
ProxySum operator[](std::size_t i) const { return ProxySum(x[i],y[i]); }
//ProxySum &operator[](std::size_t i){ return ProxySum(x[i],y[i]); }
size_t size() const { return x.size(); }
};
template<typename T,typename X,typename Y>
MatrixSum<T,X,Y>
operator+(X const& x, Y const& y)
{
return MatrixSum<T,X,Y>(x,y);
}
I am getting two errors when using the Matrix class. First is the operator+ does not exist for Matrix (I used int from testing) even though I have implemented operator overloading for '+', and another error is in the second constructor for Matrix. It says that the call I have made for the constructor of mat variable is invalid.But vectors do have such constructor
1) The following line is not a valid C++ syntax:
mat(m,std::vector<T>(n));
You should initialize mat member object in the constructor's initialization list, like this (assuming the outermost initializer_list is not empty):
Matrix(std::initializer_list<std::initializer_list<T>> lst) : mat(lst.size(), std::vector<T>(begin(lst)->size()))
2) As for the operator + you provided:
template<typename T,typename X,typename Y>
MatrixSum<T,X,Y>
operator+(X const& x, Y const& y)
{
return MatrixSum<T,X,Y>(x,y);
}
Note that T template parameter is non-deducible, so the compiler cannot figure it out and thus cannot use this operator. The only way to call it would be like this:
matrix1.operator +<some_type>(matrix2);
...which is probably not what you want.
The right way would be to try and compute T at compile-time, based on X and Y types, using some metaprogramming.
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;
}
I want to pass two functions with different signature into a same slot of class template parameter (one each time).
Ignore the strict syntax, this is what I want :-
void hf1 (int a) { std::cout<< "hf1" <<std::endl; }
void hf2 (int a, int i){ std::cout<< "hf2 "<<i<<std::endl; }
template<hfX> class Collection{
int i_=56;
public: test(){
if( "hfX has 1 param" ){hfX(0);} //call hf1
else {hfX(0,i_);} //call hf2
}
};
int main(){
Collection<&hf1> test1; test1.test(); // print "hf1"
Collection<&hf2> test2; test2.test(); // print "hf2 56"
}
Here is the code that works OK, but its usage is not so convenient :-
template<typename ... AA> using hfX = void(*)(AA ... );
void hf1 (int a) { std::cout<< "hf1" <<std::endl; }
void hf2 (int a, int i) { std::cout<< "hf2 "<<i <<std::endl; }
template <typename Tf, Tf F>
class Collection;
template <typename ... I, hfX<I...> F>
class Collection<hfX<I...>, F>{
public:
int i_=56;
template <std::size_t N = sizeof...(I)>
typename std::enable_if<N == 1U, void>::type test (){
F(0);
}
template <std::size_t N = sizeof...(I)>
typename std::enable_if<N == 2U, void>::type test (){
F(0,i_);
}
};
The usage:-
int main () {
Collection<hfX<int>, hf1> test1; //<--- #A dirty signature
Collection<hfX<int,int>, hf2> test2; //<--- #B dirty signature
test1.test(); // print "hf1"
test2.test(); // print "hf2 56"
}
Live version : https://ideone.com/f20BEk
Question
It would be nice if I can call it without explicit redundant signature.
Collection<hf1> test1; //or &hf
Collection<hf2> test2;
How to improve code (especially around hfX and Collection) to make its usage easier?
I don't know how to make what do you want with functions.
But if you can, instead of functions, accept to use static method in classes or structs (and pass that classes/structs as template argument)...
#include <iostream>
struct sf1
{ static void hf (int a) { std::cout << "hf1" << std::endl; } };
struct sf2
{ static void hf (int a, int i) { std::cout << "hf2 " << i << std::endl; } };
template <typename S>
class Collection
{
private:
int i_ = 56;
public:
template <typename T = S>
decltype(T::hf(0)) test() { S::hf(0); /*call sf1::hf */ }
template <typename T = S>
decltype(T::hf(0, 0)) test() { S::hf(0,i_); /*call sf2::hf */ }
};
int main ()
{
Collection<sf1> test1; test1.test(); // print "hf1"
Collection<sf2> test2; test2.test(); // print "hf2 56"
}
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.
I have some code which, very much simplified, looks somewhat like this:
#include <iostream>
#include <type_traits>
namespace X {
struct Foo {int x;};
struct Bar {int x;};
template <typename T , typename = typename std::enable_if<
std::is_same<decltype(T::x),int>::value
>::type>
std::ostream & operator<<(std::ostream & os, const T&) {
return os;
}
}
namespace Y {
struct Faa : X::Foo {int y;};
struct Baz {int x; int y;};
template <typename T , typename = typename std::enable_if<
std::is_same<decltype(T::x),int>::value &&
std::is_same<decltype(T::y),int>::value
>::type>
std::ostream & operator<<(std::ostream & os, const T&) {
return os;
}
}
int main() {
// Everything is ok
X::Foo x;
std::cout << x;
Y::Baz k;
std::cout << k;
// Problems..
Y::Faa y;
// std::cout << y; // <--operator is ambiguous
Y::operator<<(std::cout, y);
return 0;
}
Is there any way to avoid the ambiguous operator for Y::Faa and having to manually specify Y::operator<<? If not, why?
Two functions have a conflict because conditions on their arguments have non-empty intersection (actually, 1st supersedes 2nd). Function overloading works only if signatures are different. So, to solve this we have 2 options:
Change conditions so that they have empty intersection (manually forbid having y field by adding && !sfinae_has_member_y<T>::value condition to the 1st enable_if)
template<typename T>
struct sfinae_has_member_y {
static int has(...);
template<typename U = T, typename = decltype(U::y)>
static char has(const U& value);
enum { value = sizeof(char) == sizeof(has(std::declval<T>())) };
};
OR use another C++ feature that supports arguments overlapping, like struct/class template specialization. If you replace bool with int, other fields may be added too:
template<typename T, bool>
struct Outputter {
};
template<typename T>
struct Outputter<T, false> {
static std::ostream & output(std::ostream & os, const T&) {
os << "x";
return os;
}
};
template<typename T>
struct Outputter<T, true> {
static std::ostream & output(std::ostream & os, const T&) {
os << "y";
return os;
}
};
template<typename T, typename = std::enable_if_t<std::is_same<decltype(T::x), int>::value>>
std::ostream & operator<<(std::ostream & os, const T& a) {
return Outputter<T, sfinae_has_member_y<T>::value>::output(os, a);
}