Reputation: 18178
I've got a class foo
to which I want to pass an object of type T
together with a "deleter-like" function with signature void (T)
. Currently I'm storing this function as an object m_bar
of type typedef void (*bar_t)(T);
inside foo
.
This works without a problem as long as the function I want to use precisely matches the aforementioned signature. However, if the desired function has an additional parameter and I need to pass a specific non-constant value to it, I've tried to pass a lambda function which captures this value by value; but now I'm receiving the compiler error cannot convert from 'initializer list' to 'foo<int>'
in the example code below:
`
template<typename T>
struct foo
{
typedef void (*bar_t)(T);
foo(T t, bar_t bar)
: t(t),
bar(bar)
{}
~foo() { bar(t); }
T t;
bar_t bar;
};
void bar1(int x) {}
void bar2(int* x) {}
void bar3(int, int* x) {}
template<typename T, class Bar>
foo<T> make_foo(T t, Bar bar) { return { t, bar }; }
int main()
{
int x = 47, y = 0;
foo f1(x, bar1);
foo f2(x, [](int x) { bar2(&x); });
auto f3a = make_foo(x, [y](int x) { bar3(0, &x); }); // ok
auto f3b = make_foo(x, [y](int x) { bar3(y, &x); }); // compiler error
}
Can we solve this issue without storing a std::function
inside in foo
?
Upvotes: 0
Views: 58
Reputation: 10982
In the very restricted case where you know y
value at compile-time this works:
template <typename T>
struct foo
{
typedef void (*bar_t)(T);
foo(T t, bar_t bar) : t(t), bar(bar) {}
~foo() { bar(t); }
T t;
bar_t bar;
};
template <typename T, typename Y, Y y>
auto create_lambda()
{
return [](T x) { std::cout << x + y << "\n"; };
}
int main()
{
foo<double> f1(1.5, create_lambda<double, int, 1>());
foo<double> f2(1.5, create_lambda<double, int, 2>());
}
and prints
3.5
2.5
Upvotes: 0
Reputation: 217085
You basically have 2 choices:
Add extra template parameter:
template<typename T, typename DeleterLike>
struct foo
{
using bar_t = DeleterLike;
foo(T t, bar_t bar)
: t(t),
bar(bar)
{}
~foo() { bar(t); }
T t;
bar_t bar;
};
use some type erasure on the type (as std::function
)
template<typename T>
struct foo
{
using bar_t = std::function<void(const T&)>;
foo(T t, bar_t bar)
: t(t),
bar(bar)
{}
~foo() { bar(t); }
T t;
bar_t bar;
};
Upvotes: 3