I have a bunch of very similar functions:
void foo1(Obj o) {
bar(o.a);
}
void foo2(Obj2 o) {
bar(o.b);
}
void foo3(Obj3 o) {
bar(o.c);
}
How can I reduce the duplicating of code? Can I do something like:
template<typename T, pointerToMember>
void foo(T o) {
bar(o.pointerToMember);
}
And then create all functions like:
foo<Obj, Obj.x>;
...
?
Yes it is possible to have a pointer to member as template parameter:
#include <string>
struct Obj {
int a,b,c;
};
void bar(int x){}
template<typename T, int (T::*pointerToMember)>
void foo(T o) {
bar(o.*pointerToMember);
}
int main() {
Obj x;
foo<Obj,&Obj::a>(x);
}
However, there are different ways that would make the call less verbose. You could pass the member pointer as parameter to be able to deduce it, that would allow to call it as
foo(x,&Obj::a);
Last not least, you could call bar directly
bar(x.a);
Related
Suppose that a class has a member function which should accept either a double(double) function or a class instance with a "MyStructFunc" public member function as an argument:
#include<functional>
#include <type_traits>
struct Caller
{
// (1.)
double call(std::function<double(double)> func) { return func(1); }
// (2.)
template<typename T>
double call(const T& S) { return S.MyStructFunc(2); }
};
So, for example, we can pass
double myFunc(double x) { return x * x * x; }
or
struct myStruct
{
double MyStructFunc(double x) const { return x * x; }
};
like this:
int main()
{
Caller c;
myStruct ms;
c.call(myFunc);
c.call(ms);
}
Unfortunately, I get an error. Could you please help me make it work? Thank you for your help!
function pointer is not a std::function, so your template method is a better match.
You might use SFINAE to restrict your template method:
// (2.)
template<typename T>
auto call(const T& S) -> decltype(S.MyStructFunc(2)) { return S.MyStructFunc(2); }
Demo
Some code I have no control over has a number of overloaded functions which accepts different types
i.e.
setValue(int)
setValue(std::string)
setValue(bool)
And I have a template function which would idealy take any one of these types and pass it on to the correct setValue function.
template <class T>
do_something(T value) {
...
setValue(value);
But I get this error
error: call to member function 'SetValue' is ambiguous
Is there anything I can do to work around this problem without copy and pasting my code for each type like the writers of setValue have?
by defining you own SetValue with exact match and forwarding to the correct overload.
void setValue(int i) { setValue(static_cast<double>(i)) }
or (if you have a lot of "setValue" functions with same type) you may help the compiler to choose which overload to use like this:
void setValue(char a);
void setValue(double a);
template <typename T>
struct TypeToUseFor
{
typedef T type;
};
template <>
struct TypeToUseFor<int>
{
typedef double type;
};
template <class T>
void func(T value)
{
setValue(static_cast<typename TypeToUseFor<T>::type>(value));
// setValue(value);
}
int main() {
func(0); // int -> ?
func('0'); // exact match
func(0.0); // exect match
func(0.f); // float -> double
return 0;
}
I have no problems with:
void setValue(int a)
{
}
void setValue(std::string a)
{
}
void setValue(bool a)
{
}
template <class T>
void func(T value)
{
setValue(value);
}
int main()
{
func(5);
}
Here is my run: http://codepad.org/1wq8qd7l
I'm playing with functors. I'm using the standard example below:
class C {
public:
template <typename Func>
void foo(Func fun)
{
fun();
}
};
struct S {
void operator()() { printf ("in S\n"); }
};
....
C myClass;
myClass.foo (S());
This works nicely and I don't need to explicitly provide the S template type in the call to foo(), it just figures it out. But suppose I want to store the functor as a member variable and call it later:
class C {
public:
template <typename Func>
void foo(Func fun) {
_myFunc = fun;
}
void someOtherThing() {
_myFunc();
}
private:
WHAT_IS_THIS_TYPE _myFunc;
};
Do I now need to make the whole class a template? If so, can the compiler infer the template type as it did with the single functor, or must I provide it explicitly? Thanks.
You can use std::function (in C++11) or boost::function to store callable objects (functions, functors). It implements type erasure pattern.
class C {
public:
template <typename Func>
void foo(Func fun) {
_myFunc = fun;
}
void someOtherThing() {
_myFunc();
}
private:
std::function<void()> _myFunc;
};
Here's a hand-made way to avoid making class C a template:
struct C {
template <typename Func>
void foo(Func fun) {
_myFunc = static_cast <void*>(&fun);
stub = call <Func>;
}
void someOtherThing() {
stub(_myFunc);
}
private:
void* _myFunc;
void (*stub)(void*);
template <typename F>
static void call(void* f) {
(*static_cast <F*>(f))();
}
};
struct S {
void operator()() { std::cout << "in S" << std::endl; }
};
int main()
{
S s;
C myClass;
myClass.foo(s);
myClass.someOtherThing();
}
When you call foo(), type Func is "stored" inside the template static function call, a pointer to (an instatiation of) which is stored in stub. The latter is called by someOtherThing to actually invoke _myFunc, which is nothing but plain void*. For this to happen, _myFunc is first cast back to the correct type, which is only known inside call's body.
The only catch is that using pointers to functions there can be no inlining for stub(...) call.
I have a simple class A, providing a variadic function template. This function uses private data from within A, but the function itself is public. The class goes as follows:
class A {
public:
A() :
_bla("bla: ") {
}
template <class T>
void bar(const T& value) {
std::cout << _bla << value << std::endl;
}
template <class H, class... T>
void bar(const H& value, const T&... data) {
std::cout << _bla << value << std::endl;
bar(data...);
}
private:
const std::string _bla;
};
In a separate file, named foo.hpp, I have a function foo(), that should be able to receive and use the function a.bar() as an argument:
int main(int argc, char *argv[]) {
A a;
a.bar(1, "two", 3, 4);
foo(&a.bar);
}
I'm not very sure of where to start, but I've tried the following -- which does not work. How can I do it correctly:
template <typename... T>
inline void foo(void (bar *)(const T&...)) {
unsigned int x(0), y(0), z(0);
bar(x, y, z);
}
Bonus question: is there a way to call not only:
foo(&a.bar);
but also call foo with a.bar bound to some parameters, like:
foo(&(a.bar(p1, p2));
I can simply add p1 and p2 to foo definition itself, like in:
foo(p1, p2, &a.bar);
but it would be semantically better to my purpose if I could add these parameters before.
You cannot pass the address of a function template without instantiating it, because that is treated as a whole overload set (no matter whether the template is variadic or not). You can, however, wrap it in a generic functor:
struct bar_caller
{
template<typename... Ts>
void operator () (A& a, Ts&&... args)
{
a.bar(std::forward<Ts>(args)...);
}
};
And then let your function foo() be defined as follows:
template<typename F>
inline void foo(A& a, F f) {
unsigned int x(0), y(0), z(0);
f(a, x, y, z);
}
So your function call in main() would become:
int main()
{
A a;
a.bar(1, "two", 3, 4);
foo(a, bar_caller());
}
Unfortunately, at the moment there is no way in C++ to easily wrap an overload set in a functor without defining a separate class - as done above for bar_caller.
EDIT:
If you do not want to pass an A object directly to foo(), you can still let your bar_caller encapsulate a reference to the A object on which the function bar() has to be called (just take care of object lifetime, so that you won't be making that reference dangling):
struct bar_caller
{
bar_caller(A& a_) : a(a_) { }
template<typename... Ts>
void operator () (Ts&&... args)
{
a.bar(std::forward<Ts>(args)...);
}
A& a;
};
You could then rewrite foo() and main() as follows:
template<typename F>
inline void foo(F f) {
unsigned int x(0), y(0), z(0);
f(x, y, z);
}
int main()
{
A a;
a.bar(1, "two", 3, 4);
foo(bar_caller(a));
}
I have a template class in C++ (somewhat simplified):
template<typename T>
struct C
{
T member;
void set(const &T x) { member = x; }
void set(int x) { member = x; }
};
As you can see the set() function can be called either with the type T, or with an int. This works fine unless T is an int, in which case I get an ambiguous conversion error. I understand why this is happening, but is there any way to implement what I want?
Provide a specialisation for int:
template<>
struct C<int>
{
int member;
void set(int x) { member = x };
};
?
One way around this would be to provide a specialisation of the template for int that only has one set function. Otherwise you might want to have a look at the Boost libraries if something like enable_if in their template meta programming code would allow you to turn on the function set(int x)only when T is not of type int.
could you cast the call to either int or const int in the calling code?
It depends what you're really trying to do. Your example as written doesn't make much sense as you're trying to set member, which is a T, from x, which is an int. While there are cases that may make sense I suspect in your real code you're setting something else.
Does the method have to have the same name? If so why?
Does specialising the struct for int make sense?
What other constraints do you have?
Perhaps this would work for you:
template<typename T>
struct C
{
T member;
template<typename U>
void set(const U& x) { member = x; }
void set(int x) { member = x; }
};
Now set(int) overloads set(const U&). set(const U&) accepts non T parameters, but will probably fail when you try to assign to X. It may allow more conversions than set( const T&).
If that's not good enough, adding an extra level of indirection should do the trick:
template<typename T>
struct C
{
T member;
void set(const T& x) { setInternal( x ); }
private:
template<typename U>
void setInternal(const U& x) { member = x; }
void setInternal(int x) { member = x; }
};
It appears that you want to make the set method available only if the argument is T or int. However, if you just specialize C for int, all the implicit conversions still happen, just as if you didn't attempt to treat int type in a special way at all.
If you really want to disable implicit conversions, one way is with boost::enable_if - make the method only available, if the criteria are satisfied.
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
template<typename T>
struct C
{
T member;
template <class U>
typename boost::enable_if_c<
boost::is_same<T, U>::value || boost::is_same<U, int>::value
>::type
set(const U& x) { member = x; }
};
int main()
{
C<int> i;
i.set(3.14); //error
i.set(10); //OK
i.set('a'); //error
C<double> d;
d.set(3.14); //OK
d.set(3.14f); //error
d.set(10); //OK
d.set('a'); //error
}
To achieve the same result without boost::enable_if (or implementing it yourself), you might also need to make all unwanted versions of set private (C++0x also allows to delete these overloads).
template<typename T>
struct C
{
T member;
void set(const T& x) { member = x; }
void set(int x) { member = x; }
private:
template <class U>
void set(const U&);
};
template <>
struct C<int>
{
int member;
void set(int x) { member = x; }
private:
template <class U>
void set(const U&);
};
int main()
{
C<int> i;
i.set(3.14); //error
i.set(10); //OK
i.set('a'); //error
C<double> d;
d.set(3.14); //OK
d.set(3.14f); //error
d.set(10); //OK
d.set('a'); //error
}
However, making this exception for int seems rather arbitrary to me. Conversions from int might not be particularly safe, either, e.g int->float might lose precision for large values, int->short / int->char / int->unsigned might overflow.