using template arguments to specify policy - c++

I got to know that we can also pass template arguments to choose which function should execute. I found them good alternative to function pointers since function pointers has run time cost but template parameters does not. Also, template parameters can be made inline whereas function pointers are not.
Alright then, this is what I wrote to depict my understanding on it. I came close but missing some minor detail somewhere.
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.length()) && (i < str2.length()); ++i) {
if (C::eq(str1[i], str2[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<String<std::string>, Cmp1<std::string> >(s, t);
// compare(s, t);
}
Details of the code:
I have an class String, which take an parameter and create member function of that type.
I have an compare function, which takes two String& arguments. Comparison function is passed to it.
Cmp1 and Cmp2 are two compare functions.
compare<String<std::string>, Cmp1<std::string> >(s, t);
does not get compile here. I tried some other ways to call but in vain.

Looks like you want something like that:
#include <iostream>
#include <string>
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.str.length()) && (i < str2.str.length()); ++i) {
if (C::eq(str1.str[i], str2.str[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
public:
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
public:
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<std::string, Cmp1<char> >(s, t);
// compare(s, t);
}
code
Explanations:
You already have String in definition of compare, you need to just send T which is std::string in your case.
You are trying to go through entire std::string, in compare, so, now your code compiles.
You calling cmp on str[index], that is actually char, so you need to call cmp with char template argument.

Related

Compilation Error on Accessing member function for Template Objects

I'm just getting started with Object Oriented Programming. I'm trying to access member function of two different classes within a template function. I have restricted access to member functions based on boolean flag isAggregateElement. For some reason, Compiler throws error stating that there is no such member function.
class descriptor{
public:
int getName(){
return -5;
}
};
class aggregate{
public:
int getDescription() {
return 234;
}
int getUnit(){
return 1;
}
};
template <typename T>
void buildObjectInfo(const T& classMemberType, const bool& isDataInterface){
T baseTypeElement = classMemberType;
bool isAggregateElement = !isDataInterface;
if(isAggregateElement){
cout<<baseTypeElement.getUnit()<<endl;
} else {
cout<<baseTypeElement.getName()<<endl; // Error gets resolved if I remove the else construct
}
}
int main()
{
aggregate a;
descriptor d;
buildObjectInfo<aggregate>(a,false);
return 0;
}
What should I do to access getUnit() without deleting boolean condition (or) removing else construct in the template function ?
Both branches must be valid. Suppose you call buildObjectInfo(d,false), what should happen then?
You can use constexpr if to discard the false branch.
Note that the getters should be const methods. The template argument can be deduced from the function parameter and you do not need the bool:
#include <iostream>
#include <type_traits>
struct descriptor{
int getName() const { return -5; }
};
struct aggregate{
int getDescription() const { return 234; }
int getUnit() const { return 1; }
};
template <typename T>
void buildObjectInfo(const T& t){
if constexpr(std::is_same_v<aggregate,T>) {
std::cout << t.getUnit() << '\n';
} else {
std::cout << t.getName() << '\n';
}
}
int main() {
aggregate a;
descriptor d;
buildObjectInfo(a);
buildObjectInfo(d);
}
However, for only 2 different types an overloaded function is much simpler:
#include <iostream>
struct descriptor{
int getName() const { return -5; }
};
struct aggregate{
int getDescription() const { return 234; }
int getUnit() const { return 1; }
};
void buildObjectInfo(const aggregate& t) {
std::cout << t.getUnit() << '\n';
}
void buildObjectInfo(const descriptor& t) {
std::cout << t.getName() << '\n';
}
int main() {
aggregate a;
descriptor d;
buildObjectInfo(a);
buildObjectInfo(d);
}

Why can't I call operator()?

I am trying to understand different topics in C++ by examples and I cannot get this example to work:
template<typename T>
class zero_init
{
T val;
public:
zero_init() : val(static_cast<T>(0)) { std::cout << "In constructor with no parameters\n"; }
operator T() const { std::cout << "In operator T()\n"; return val; }
};
int main()
{
const zero_init<int> x;
x(); //Error!
return 0;
}
I am obviously trying to call the operator() but it gives the error: "call of an object of a class type without appropriate operator()"
You accidentally implemented a type conversion operator and not operator(). Overload operator() like this instead (I removed the return value because you discard it in main anyway):
#include <iostream>
template<typename T>
class zero_init
{
T val;
public:
zero_init() : val(static_cast<T>(0)) { std::cout << "In constructor with no parameters\n"; }
void operator()() const { std::cout << "In operator()\n"; }
};
int main()
{
const zero_init<int> x;
x();
return 0;
}
If you actually need the return value, do it like this:
#include <iostream>
template<typename T>
class zero_init
{
T val;
public:
zero_init() : val(static_cast<T>(0)) { std::cout << "In constructor with no parameters\n"; }
T operator()() const { std::cout << "In operator()\n"; return val; }
};
int main()
{
const zero_init<int> x;
auto val = x();
return 0;
}

Substituting a method with const qualifier change (C++)

Suppose we need to instantiate a function that calls some class method from inside non-trivial code.
#include <iostream>
class A
{
public:
int f() { return 1; }
int g() { return 2; }
};
template <class T, int (T::*method)()>
int func(T& x)
{
// some complex code here calling method()
return (x.*method)();
}
int main()
{
A a;
std::cout << func<A, &A::f>(a) << "\n"
<< func<A, &A::g>(a) << "\n";
return 0;
}
This code compiles and works fine. Now suppose that the two methods are actually const and non-const, like this:
class A
{
int val_;
public:
A() : val_(0) {}
int alloc() { return ++val_; }
int get() const { return val_; }
};
This time we can't use the same approach, because the member functions have different signatures due to const qualifier. Moving the problem to run time does not seem to solve anything, Is there a way to avoid rewriting func() as two functions in this situation?
Can you change passing method from template parameter to function parameter?
If yes, this works:
#include <iostream>
class A
{
public:
int f() { return 1; }
int g() const { return 2; }
};
template <class T, class F>
int func(F method, T& x)
{
// some complex code here calling method()
return (x.*method)();
}
int main()
{
A a;
std::cout << func(&A::f, a) << "\n"
<< func(&A::g, a) << "\n";
return 0;
}

How can I detect if the instance is const from a member function?

I would like to write a member function which detects if the instantiated object is const.
To give a simple example, we can consider the following class definition
class Foo{
public:
void constnessChecker(){
bool isConst;
// MORE CODE GOES HERE...
if (isConst) {
std::cout << "This instance is const! << std::endl;
} else {
std::cout << "This instance is not const! << std::endl;
}
}
};
and the following code
int main(){
Foo foo1;
Foo const foo2;
foo1.constnessChecker();
foo2.constnessChecker();
}
which should produce
This instance is not const!
This instance is const!
Is this possible?
Provide const and non-const overloads:
class Foo
{
public:
void constnessChecker(){
std::cout << "This instance is not const\n";
}
void constnessChecker() const {
std::cout << "This instance is const\n";
}
....
};
In the style of boost::is_const or std::is_const, you can also write up the following:
#include <iostream>
template <typename T>
struct is_const
{
static const bool value = false;
};
template <typename T>
struct is_const<const T*>
{
static const bool value = true;
};
struct S
{
void f() const
{
std::cout << is_const<decltype(this)>::value << std::endl;
}
void f()
{
std::cout << is_const<decltype(this)>::value << std::endl;
}
int m;
};
int main(int argc, char** argv)
{
const S& cs = S(); // note that choosing a const-ref is merely to force the compiler to choos S::f() const!
cs.f (); // prints 1
S().f (); // prints 0
return 0;
}
I haven't looked at the implementation of std::is_const but for some reason it returns false where the above is_const returns true.
Note: Obviously you need support for decltype and thus the above will only work for C++11 compliant compilers.

Strange? behaviour of cout

Why executing this code:
// DefaultAny.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <exception>
using std::cout;
template<class T>
struct NoReturnPolicy
{
static void calculate(T& result, const T& source)
{
result = source;
}
};
template<class T>
struct ReturnPolicy
{
static T& calculate(T& result, const T& source)
{
result = source;
return result;
}
};
template<class T>
struct ThrowPolicy
{
static void check(T* ptr)
{
cout << "ThrowPolicy";
struct Nullptr: public std::exception{};
if(!ptr)
{
throw Nullptr("Nullptr not allowed");
}
}
};
template<class T>
struct NoThrowPolicy
{
static T* check(T* ptr)
{
cout << "NoThrowPolicy";
if(!ptr)
{
return nullptr;
}
else
{
return ptr;
}
}
};
/*
If pointer already points at
something no assignement is being done
*/
template<class T, class ThrowingPolicy>
struct NoAssignPolicy
{
static T* check(T* dest,const T*const src)
{
cout << "NoAssignPolicy";
if (!ThrowPolicy::check(dest))
{
dest = operator new(sizeof(T));
new (dest) T(*src);
}
}
};
template<class T,class ThrowingPolicy>
struct NoCheckPolicy
{
static void check(T* p)
{
cout << "NoCheckPolicy";
}
};
template<class T,class ThrowingPolicy>
struct CheckPolicy
{
static void check(T* p)
{
cout << "CheckPolicy";
ThrowingPolicy::check(p);
}
};
template<
class T,
class ThrowingPolicy = NoThrowPolicy<T>,
class CheckingPolicy = NoCheckPolicy<T,ThrowingPolicy>,
class AssigningPolicy = NoAssignPolicy<T,ThrowingPolicy>,
class ReturningPolicy = NoReturnPolicy<T>
>
struct BreadSlicer
{
BreadSlicer()
{
cout << "Type: " << typeid(T).name() << '\n';
cout << "ThrowingPolicy: " << ThrowingPolicy::check(0) << '\n'; //
//<<<---------The second call to cout makes output on my console:
//NoThrowPolicy:"NoSpace"ThrowingPolicy:"Space"000000
}
};
//The words NoSpace and Space do not actually appear in my console ;) and they are in the opposite order.
int _tmain(int argc, _TCHAR* argv[])
{
BreadSlicer<int> a;
return 0;
}
See comments in first struct above main.
This is the result of unspecified behavior. If you have:
cout << a() << b() << c() << endl;
The order of execution of a, b, and c is not defined (yes, their results are added to the cout stream in a predictable order, but execution of the functions is not in defined order).
If your question is why "NoThrowPolicy" gets output before "ThrowingPolicy", the answer is that there's no sequence point guaranteeing an ordering for the call to ThrowingPolicy::check(0) and the call to operator<<(cout, "ThrowingPolicy: "). C++ is allowed to call those functions in either order.