Why is the static keyword needed in this template code? - c++

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!

Related

templated function as a parameter to another templated function

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

static function as class template parameter - cause maintainability issue

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]; }

Callback an unknown class+function

My C++ is rusty. I'd like MyClass to know nothing about Foo and have a callback to run a function in foo. I don't know how to define callback_pair or how to call SetCallback
class MyClass{
tuple<cb, ptr> callback_pair
int run() {
auto that=callback_pair<1>();
auto cb = callback_pair<0>();
int a=1, b=2, c=3;
auto result = cb(that, a, b, c); //this calls foo.the_function
return result;
}
void SetCallback(tuple<cb, ptr> cb) { callback_pair=cb; )
};
class Foo {
int d;
int the_func(int a, b, c) {
return a+b+c+d
}
}
//myclass.SetCallback(what_do_I_write_here)
Well, MyClass must know something about Foo, namely the signature of whatever method you plan on using as a callback; otherwise, how would it know what to pass in as parameters, or what type to expect to get as output? If the callback signature is known and fixed, for instance int(int,int,int) as you have above, you could use a construction like this:
class MyClass {
std::function<int(int,int,int)> callback;
public:
int run() {
return callback(1,2,3); // or whatever
}
template <typename Class>
void SetCallback (Class& o, int (Class::*m) (int,int,int)) {
callback = [&o,m] (int a, int b, int c) { return (o.*m)(a,b,c); };
}
template <typename Class>
void SetCallback (Class const& o, int (Class::*m) (int,int,int) const) {
callback = [&o,m] (int a, int b, int c) { return (o.*m)(a,b,c); };
}
};
The above implementation of MyClass works as follows: callback is a function object, initially undefined, which takes three ints and returns an int. SetCallback takes two parameters: An object o on which the callback should be performed and a method m on that object which conforms to the signature of callback. It doesn't care what the type of o is; thanks to type-erasure, MyClass never needs to know what it's actually calling.
Take special notice of the two versions of SetCallback -- one each for const and non-const objects. In reality, you should be writing overloads for volatile and const volatile as well, but those are comparatively much rarer than const. In the future, once exception specifications and transactions become part of the type system, we will also have to care about noexcept and synchronization, and the resulting combinatoric explosion of types will be difficult to deal with effectively without some very clever language support. But this example shows you how that sort of code would be written, and it's probably good enough for your purposes.
The implementation looks ugly, but it actually provides a very clean interface; given Foo as you've written above, you would use MyClass's callback functionality like this:
MyClass test;
Foo foo;
foo.d = 4;
test.SetCallback (foo, &Foo::the_func);
int result = test.run(); // result = 10
The above code will work with any type that has a method with the signature int(int,int,int). Note that you must call SetCallback before you call run, or else you'll get a std::bad_function_call exception because the callback hasn't been defined yet.

Function pointer and Template

Why does the following code work?
class foo {
public:
template <typename F>
int Map(F function) const {
return function(2);
}
};
int Double(int n) {
return 2*n;
}
int main(){
foo f;
int n = f.Map(Double);
}
My understanding is that the function accepting the function pointer must have format such as:
void foo(int (*ptf)(int))
So the Map function should look like
int Map(int (*ptf)(int)){
return (*ptf)(2);
}
does the it somehow resolve the function at run-time or at compile-time through template?
the above code was compiled and ran in vc++ 2010
Template are a compile-time concept, so of course it will be resolved during compile time (if what you mean is the template parameter substitution). Try passing something which you can't call like function(2), e.g., some int. This will yield a compile-time error. After substitution, your function will look like
int Map(int (*function)(int)){
return function(2);
}
You don't explicitly need to dereference a function pointer, because both function(2) and (*function)(2) are immediatly converted to a so-called function designator. That itself is dereferenceable again and you can build an endless chain: (***********function)(2) will still work and is still the same as function(2) and (*function)(2).

Passing class template as a function parameter

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) {
}
}