This question is a result of my lack of understanding of a situation, so please bear if it sounds overly stupid.
I have a function in a class, like:
Class A {
void foo(int a, int b, ?)
{
----
}
}
The third parameter I want to pass, is a typed parameter like
classA<classB<double > > obj
Is this possible? If not, can anybody please suggest a workaround? I have just started reading about templates.
Thanks,
Sayan
Doesn't it work if you just put it there as a third parameter?
void foo(int a, int b, classA< classB<double> > obj) { ... }
If it's a complex type it might also be preferable to make it a const reference, to avoid unnecessary copying:
void foo(int a, int b, const classA< classB<double> > &obj) { ... }
You can use a member template:
Class A{
template <typename T>
void foo(int a, int b, T &c) {
}
}
Related
I have an utility function which takes two values and does something on another object if two values meet a certain criteria.
So, the utility function has to take a member function as a std:function and also sometimes as a free flowing function.
class A
{
public:
void fun(int a) {}
};
template <typename T>
bool ifSet(T a, T b, std::function<void(T)> f )
{
if (a == b) return false;
else return f(b);
}
int main() {
auto p = std::make_shared<A>(new A);
std::cout<< ifSet(10, 10, std::bind(A::fun, p, std::placeholders::_1));
The above code is my dummy implementation, but doesn't work. Can someone suggest me a better code ?
Your
std::function<void(T)> f
return a void and you use it as return for bool ifSet() function
After I learned how to pass static function (HashFunction) as a class (Collection<T,HashFunction>) template parameter, I am very addicted to it.
I use it in many places ... now I just realize that if I want to change HashFunction's signature, I will be obliged to modify code in various location.
Example
There are some classes (B and C) that are designed to be used as element of a custom collection (Collection<T,HashFunction>):-
class B{
int bHash;
public: static int& getHash(B& b){return b.bHash;} //#1
//.... other complex thing about B ....
};
class C{
int cHash1;
public: static int& getHash1(C& c){return c.cHash1;} //#2
int cHash2;
public: static int& getHash2(C& c){return c.cHash2;} //#3
//.... other complex thing about C ....
};
//There are about 20 places, i.e. #1 to #20
//They have a thing in common : return an integer field
The Collection<T,HashFunction> (its code is not shown) works similar as a hashset of T.
Here is the usage:-
Collection<B,&B::getHash> collectB;
Collection<C,&C::getHash1> collectC1;
Collection<C,&C::getHash2> collectC2;
//There are about 30+ locations.
Problem
Signature of the hash function (#1,#2,#3 and inside Collection) may require change in the future.
For example, the signature may change from
int bHash;
static int& getHash(B& b){return b.bHash;}
to
HashStructure bHash; //"HashStructure" is a new class
static HashStructure& getHash(B& b,int notUsed){return b.bHash;}
//They tend to still have a thing in common : return a "HashStructure" field
//Here is the maximum possible difference :-
HashStructure bHash[3];
static HashStructure& getHash(B& b,int index){return b.bHash[index];}
//They are likely consistent for both B and C.
Changing Collection to use the new signature is not hard, but changing all signature of #1 to #20 is tedious.
This indicates a maintainability problem.
Question
Suppose I can reverse time to when there are only #1 to #3,
how to modify the code/design (in the example) to prevent maintainability problem.
Opinions:
I should use inheritance (A and B derived from a new class),
but it doesn't fit. (Because B can have unlimited amount of hash function. Moreover, the names of hash function are likely different from A's.)
Some certain design pattern might help. (?)
Variadic template and SFINAE might help. (from Danh's comment, thank!)
To prevent the maintainability problem, I would not have used functions as template arguments in the first place. I would have gone for a 1 type == 1 hash function design, similar to what the STL does to solve the same problem.
Whichever reason you have to stick the different hash functions into the same class can be solved using either inheritance or friendship.
This way, only the call sites have to be updated when the signature change. You could also provide both signatures until every call site has been updated, allowing you to update the code base step by step.
Example:
#include <utility>
class C {
static int cHash1;
};
int C::cHash1 = 0;
struct C1 : public C {
static int hash(C &value);
static int hash(C &value,bool);
};
struct C2 : public C {
static int hash(C &value);
static int hash(C &value,bool);
};
template <class Value, class HashFunction>
struct Collection {
using key_type = decltype(HashFunction::hash(std::declval<HashFunction&>()));
};
template <class Value, class HashFunction>
struct CollectionUpdated {
using key_type = decltype(HashFunction::hash(std::declval<HashFunction&>(), std::declval<bool>()));
};
int main() {
Collection<int, C1> c1;
Collection<int, C2> c2;
CollectionUpdated<int, C1> c1_up;
CollectionUpdated<int, C2> c2_up;
return 0;
}
It seems that getHash can be factorized into
template <typename T, int (T::*hash)>
int& getHash(T& t) { return t.*hash; }
Then usage is:
Collection<B, &getHash<B, &B::bHash>> collectB;
Collection<C, &getHash<C, &C::cHash1>> collectC1;
Collection<C, &getHash<C, &C::cHash2>> collectC2;
And later, you can change implementation of getHash once:
template <typename T, int (T::*hash)[3]>
static HashStructure& getHash(T& t, int index) { return (t.*hash)[index]; }
Working on a simple example for template functions. The code compiles and works as expected. But my question is why "static" is required in both "Cmp" and "Lit"? Otherwise, it will not compile?
Thanks a lot!
template<class T> class Cmp{
public:
static int work(T a, T b) {
std::cout << "Cmp\n";
return 0;
}
};
template<class T> class Lit{
public:
static int work(T a, T b){
std::cout << "Lit\n" ;
return 0;
}
};
template<class T, class C>
int compare(const T &a, const T &b){
return C::work(a, b);
}
void test9(){
compare<double, Cmp<double> >( 10.1, 20.2);
compare<char, Lit<char> >('a','b');
}
C::work(a, b) names a static member function work() of class C.
The reason that static is required here is that in the compare template function, you have this line:
return C::work(a, b);
The syntax C::work(a, b) here means "call the function work nested inside the class C. Normally, this would try to call a member function without providing a receiver object. That is, typically the way you'd call a function work would be by writing
C myCObject;
myCObject.work(a, b);
In this case, though, we don't want to be calling a member function. Instead, we want the function work to be similar to a regular function in that we can call it at any time without having it act relative to some other object. Consequently, we mark those functions static so that they can be called like regular functions.
Hope this helps!
i have something like that
class Foo {
Bar a, b, c;
void doStuffWithA();
void doStuffWithB();
void doStuffWithC();
}
instead of writing an implementation for each of the methods i want something like a template. How to do that?
Cheers,
Dirk
Edit:
I explicitly need to know which variable I do stuff with (recursion):
class Foo {
Bar a, b, c;
Foo* parent;
static void doRecursiveStuffWithA(Foo *_node) {
if(_node->parent==NULL) {
return;
} else {
doRecursiveStuffWithA(_node->parent)
}
}
static void doRecursiveStuffWithB(Foo *_node) {
if(_node->parent==NULL) {
return;
} else {
doRecursiveStuffWithB(_node->parent)
}
}
static void doRecursiveStuffWithC(Foo *_node) {
if(_node->parent==NULL) {
return;
} else {
doRecursiveStuffWithC(_node->parent)
}
}
}
Edit2:
Maybe that does explain better what my problem is:
class Foo {
public:
int a, b, c;
}
class Bar {
public:
void doStuffWithAOfFoo(Foo *_foo);
void doStuffWithBOfFoo(Foo *_foo);
void doStuffWithCOfFoo(Foo *_foo);
}
I just want to keep my code simple and not to have to implement doStuffWithX three times...
I think you want parameters...
class Foo {
Bar a, b, c;
void doStuffWithBar(Bar x);
}
Templates are for dealing with a variety of data-types and function arguments are for dealing with a variety of variables.
#Andrew White has the simplest answer. If you want a function that can do the same thing but with a variety of different values, it should take an argument.
There are cases where we legitimately want different methods that look almost identical, like getFirstName(), setFirstName(), getLastName(), setLastName(). There, using arguments would rather defeat the purpose.
The architecture there is perfectly sound (and indeed widely accepted); the only problem is the tedium of typing it all up. If you just want to avoid all the extra typing, consider using an Integrated Development Environment that offers "code templates". Both Eclipse and Visual Studio (among many others, surely) will let you select a variable and click a button to generate a getter and setter for that variable. All the code with none of the hassle.
You can use a reference:
class Foo {
Bar a, b, c;
void doStuffWithBar(Bar& what)
{
print(what);
bool flag = check(what);
if (!flag)
doStuffWithBar(what);
}
}
You can use a pointer to member:
class Foo {
Bar a, b, c;
typedef Bar (Foo::*PointerToBar);
void doStuffWithBar(PointerToBar selector)
{
print(this->*selector);
bool flag = check(this->*selector);
if (!flag)
doStuffWithBar(selector);
}
}
The latter solution is more flexible: you can choose another object and/or another member with which to continue recursion (pointers to members are obscure and are rarely used; don't use them unless you need this flexibility):
class Foo {
Bar a, b, c;
Foo* next;
typedef Bar (Foo::*PointerToBar);
void doStuffWithBar(PointerToBar selector)
{
print(this->*selector);
if (next)
next->doStuffWithBar(selector);
}
}
Code smell - design problem? The repetition here makes it feels like Bar needs a new method:
void Bar::doStuff(Foo &foo);
Then you need to figure out what is public, private and const.
Edit: Your edit changes things a little. I now really feel that there are ways your design could be improved, e.g. STL container and algorithms.
To expand a little on Andrew's solutions, you might also be looking for:
void doStuffWithBar(Bar x, Bar y, Bar z);
If you actually have BarX x, BarY y and BarZ z, then you probably want to overload your member function in your class
class Foo {
BarX x;
BarY y;
BarZ z;
void doStuffWithBar(BarX x);
void doStuffWithBar(BarY y);
void doStuffWithBar(BarZ z);
};
You might also be looking for something like (this is the ugliest solution and I wouldn't really recommend it):
void doStuffWithBar(int n)
{
if(n==0)
doSomethingWithX();
else if(n==1)
doSomethingWithY();
else if(n==2)
doSomethingWithZ();
}
Edit:
ReturnType Bar::doStuffWithBar(ParamA a, ParamB b);
I would like to know what is better to use in my situation and why. First of all I heard that using RTTI (typeid) is bad. Anyone could explain why? If I know exactly types what is wrong to compare them in a runtime? Furthermore is there any example how to use boost::type_of? I have found none searching through the mighty google :) Other solution for me is specialization, but I would neet to specialize at least 9 types of new method. Here is an example what I need:
I have this class
template<typename A, typename B, typename C>
class CFoo
{
void foo()
{
// Some chunk of code depends on old A type
}
}
So I need to rather check in typeid(what is I heard is BAD) and make these 3 realizations in example like:
void foo()
{
if (typeid(A) == typeid(CSomeClass)
// Do this chunk of code related to A type
else
if (typeid(B) == typeid(CSomeClass)
// Do this chunk of code related to B type
else
if (typeid(C) == typeid(CSomeClass)
// Do this chunk of code related to C type
}
So what is the best solution? I don't want to specialize for all A,B,C, because every type is has 3 specializations so I will get 9 methods or just this typeid check.
It's bad because
A, B and C are known at compile-time but you're using a runtime mechanism. If you invoke typeid the compiler will make sure to include metadata into the object files.
If you replace "Do this chunk of code related to A type" with actual code that makes use of CSomeClass's interface you'll see you won't be able to compile the code in case A!=CSomeClass and A having an incompatible interface. The compiler still tries to translate the code even though it is never run. (see example below)
What you normally do is factoring out the code into separate function templates or static member functions of classes that can be specialized.
Bad:
template<typename T>
void foo(T x) {
if (typeid(T)==typeid(int*)) {
*x = 23; // instantiation error: an int can't be dereferenced
} else {
cout << "haha\n";
}
}
int main() {
foo(42); // T=int --> instantiation error
}
Better:
template<typename T>
void foo(T x) {
cout << "haha\n";
}
void foo(int* x) {
*x = 23;
}
int main() {
foo(42); // fine, invokes foo<int>(int)
}
Cheers, s
Well generally solutions can be come up with without RTTI. It "can" show you haven't thought the design of the software out properly. THAT is bad. Sometimes RTTI can be a good thing though.
None-the-less there IS something odd in what you want to do. Could you not create an interim template designed something like as follows:
template< class T > class TypeWrapper
{
T t;
public:
void DoSomething()
{
}
};
then partially specialise for the functions you want to as follows:
template<> class TypeWrapper< CSomeClass >
{
CSomeClass c;
public:
void DoSomething()
{
c.DoThatThing();
}
};
Then in your class define above you would do something such as ...
template
class CFoo
{
TypeWrapper< A > a;
TypeWrapper< B > b;
TypeWrapper< C > c;
void foo()
{
a.DoSomething();
b.DoSomething();
c.DoSomething();
}
}
This way it only actually does something in the "DoSomething" call if it is going through the partially specialised template.
The problem lies in the code chunks you write for every specialization.
It doesn't matter if you write (lengthwise)
void foo()
{
if (typeid(A) == typeid(CSomeClass)
// Do this chunk of code related to A type
else
if (typeid(B) == typeid(CSomeClass)
// Do this chunk of code related to B type
else
if (typeid(C) == typeid(CSomeClass)
// Do this chunk of code related to C type
}
or
void foo()
{
A x;
foo_( x );
B y;
foo_( y );
C z;
foo_( z );
}
void foo_( CSomeClass1& ) {}
void foo_( CSomeClass2& ) {}
void foo_( CSomeClass3& ) {}
The upside of the second case is, when you add a class D, you get reminded by the compiler that there is an overload for foo_ missing which you have to write. This can be forgotten in the first variant.
I'm afraid this is not going to work in the first place. Those "chunks of code" have to be compilable even if the type is not CSomeClass.
I don't think type_of is going to help either (if it is the same as auto and decltype in C++0x).
I think you could extract those three chunks into separate functions and overload each for CSomeClass. (Edit: oh there are else if's. Then you might indeed need lots of overloads/specialization. What is this code for?)
Edit2: It appears that your code is hoping to do the equivalent of the following, where int is the special type:
#include <iostream>
template <class T>
bool one() {return false; }
template <>
bool one<int>() { std::cout << "one\n"; return true; }
template <class T>
bool two() {return false; }
template <>
bool two<int>() { std::cout << "two\n"; return true; }
template <class T>
bool three() {return false; }
template <>
bool three<int>() { std::cout << "three\n"; return true; }
template <class A, class B, class C>
struct X
{
void foo()
{
one<A>() || two<B>() || three<C>();
}
};
int main()
{
X<int, double, int>().foo(); //one
X<double, int, int>().foo(); //two
X<double, double, double>().foo(); //...
X<double, double, int>().foo(); //three
}
I think you've got your abstractions wrong somewhere.
I would try redefining A, B & C in terms of interfaces they need to expose (abstract base classes in C++ with pure virtual methods).
Templating allows basically duck-typing, but it sounds like CFoo knows too much about the A B & C classes.
typeid is bad because:
typeid can be expensive, bloats
binaries, carries around extra
information that shouldn't be
required.
Not all compilers support it
It's basically breaking the class hierarchy.
What I would recommend is refactoring: remove the templating, instead define interfaces for A, B & C, and make CFoo take those interfaces. That will force you to refactor the behaviour so the A, B & C are actually cohesive types.