Can I get default template argument from template specialization with clang AST? - c++

I want to get default template argument from a template specialization with clang AST, but can find no way.
Can anyone help me?
template<typename TT0>
struct DefaultArg
{
typedef char TypeT;
};
template<typename TT0,
typename TT1 = typename DefaultArg<TT0>::TypeT >
struct Template0
{
};
Template0<int> s; // Is there any way to get 'DefaultArg<int>::TypeT'
// ( neither DefaultArg<TT0>::TypeT nor 'char' )
// as default template argument
// for this template specialization?
AST dump for the sample

Short answer: not to my knowledge.
Work around solution...
Here is example code that does the trick:
(it only works for depth=0)
bool CheckSpecializedTemplate(const clang::QualType& Type)
{
// ignore types that are not class or struct records
if (!Type->isRecordType() || !Type->isStructureOrClassType())
return false;
// get the underlying record and make sure it is a
// specialization of a template type
const clang::CXXRecordDecl* Record = Type->getAsCXXRecordDecl();
if (Record->getKind() != clang::Decl::Kind::ClassTemplateSpecialization)
return false;
return true;
}
bool TrySubstitutionPrint(
const clang::TemplateParameterList* TemplateList,
const clang::TemplateArgumentList& ArgumentsList,
const clang::QualType& Type)
{
//
// Hack to patch in the type substitutions
// (AST doesn't seem to preserve dependent template specialization)
//
auto& out = llvm::outs();
// from the dependent type, get the nested type or return
const clang::Type* Ptr = Type.getTypePtr();
if (Ptr->getTypeClass() != clang::Type::TypeClass::DependentName)
return false;
const clang::DependentNameType* DnPtr =
static_cast<const clang::DependentNameType*>(Ptr);
const clang::NestedNameSpecifier* Nns = DnPtr->getQualifier();
if (!Nns) return false;
if (Nns->getKind() != clang::NestedNameSpecifier::SpecifierKind::TypeSpec)
return false;
const clang::Type* NestedPtr = Nns->getAsType();
if (NestedPtr->getTypeClass() != clang::Type::TypeClass::TemplateSpecialization)
return false;
const clang::TemplateSpecializationType* TsPtr =
static_cast<const clang::TemplateSpecializationType*>(NestedPtr);
const clang::TemplateDecl* Temp = TsPtr->getTemplateName().getAsTemplateDecl();
out << DnPtr->getKeywordName(DnPtr->getKeyword()).str();
out << " " << Temp->getNameAsString() << "<";
// match the args to their respective parameters
const clang::TemplateParameterList* List = Temp->getTemplateParameters();
bool Multi = false;
for (auto Token = List->begin(); Token != List->end(); Token++) {
if (Multi) out << ", "; else Multi = true;
out << (*Token)->getNameAsString();
// brute force search
int Index = 0;
for (auto T2 = TemplateList->begin(); T2 != TemplateList->end(); T2++) {
if ((*T2)->getNameAsString() == (*Token)->getNameAsString()) {
out << " = " << ArgumentsList[Index].getAsType().getAsString();
break;
}
Index++;
}
}
out << ">::";
// print the dependent type name
const clang::IdentifierInfo* identifier = DnPtr->getIdentifier();
out << identifier->getName().str();
return true;
}
bool VisitVarDecl(clang::VarDecl* Decl)
{
auto& out = llvm::outs();
clang::QualType Type = Decl->getType();
// let's only look for variables with name "s"
auto varname = Decl->getNameAsString();
if (varname != "s") return true;
// we only want specialized templates
if (!CheckSpecializedTemplate(Type)) return true;
// convert the record to a specialization and
// get the underlying template decl
const clang::CXXRecordDecl* Record = Type->getAsCXXRecordDecl();
const clang::ClassTemplateSpecializationDecl* Special =
static_cast<const clang::ClassTemplateSpecializationDecl*>(Record);
const clang::ClassTemplateDecl* Template = Special->getSpecializedTemplate();
// iterate over the list of template parameters and print them out
const clang::TemplateArgumentList& ArgsList =
Special->getTemplateArgs();
const clang::TemplateParameterList* TemplateList =
Template->getTemplateParameters();
int Index = 0;
for (clang::TemplateParameterList::const_iterator
TemplateToken = TemplateList->begin();
TemplateToken != TemplateList->end(); TemplateToken++)
{
switch ((*TemplateToken)->getKind()) {
case clang::Decl::Kind::TemplateTemplateParm: {
const clang::TemplateArgument& c = ArgsList[Index];
out << "class = " << c.getAsType().getAsString();
} break;
case clang::Decl::Kind::TemplateTypeParm: {
const clang::TemplateTypeParmDecl* ttpd =
static_cast<const clang::TemplateTypeParmDecl*>(*TemplateToken);
if (ttpd->hasDefaultArgument()) {
clang::QualType DefaultArg = ttpd->getDefaultArgument();
if (!TrySubstitutionPrint(TemplateList, ArgsList, DefaultArg))
out << DefaultArg.getAsString() << "+";
}
else out << "template " << ttpd->getNameAsString();
const clang::TemplateArgument& c = ArgsList[Index];
out << " = " << c.getAsType().getAsString();
} break;
}
out << "\n";
Index++;
}
// All done!
out << "\n";
return true;
}
The output for your code snippet would be
template TT0 = int
typename DefaultArg<TT0 = int>::TypeT = char

Related

Incompatible conversion while assigning even tho i catch it with an if statement C++11

template <typename T> using Map = std::map<std::string, T>;
class object_index {
public:
object_index(){};
int cntr = 0;
Map<int> MapInt;
Map<bool> MapBool;
Map<std::string> MapStr;
Map<double> MapDouble;
template <typename V> void insert2Map(V lhs) {
if (std::is_same<V, int>::value) {
std::cout << "INT: ";
std::string key = std::to_string(cntr);
MapInt[key] = lhs; // ERROR
/* incompatible pointer to integer conversion assigning to
'std::map<std::basic_string<char>, int>::mapped_type'
(aka 'int') from 'const char *' */
}
if (std::is_same<V, const char *>::value) {
std::cout << "STR: ";
}
if (std::is_same<V, bool>::value) {
std::cout << "BOOL: ";
}
if (std::is_same<V, double>::value) {
std::cout << "DOUBLE: ";
}
std::cout << lhs << std::endl;
}
template <typename Ob> object_index &operator,(Ob obj) {
insert2Map(obj);
++cntr;
return *this;
}
// o1[values 1.3, 2, 4, "hello"];
};
class object {
public:
void operator[](object_index index) { item = index; }
private:
object_index item;
};
#define values object_index(),
int main(void) {
object o1 = object();
o1[values 1.3, 2, true, "hello"];
return 0;
}
DISCLAIMER:: I know there is no reason to use this weird syntax , its for a Uni project that asks for this.
It should never get an argument of an incompatible type , I check for it before using it. How can i get past this? Or is the compiler right? How can I achieve this correctly?

How to pass fields from a class to function in c++?

In some words: how can I pass various fields from a custom class to a single function?
Now in details:
I have a std::vector containing a class, for example CustomClass from which I have to extract a result from a field from this class by some criteria which are fields in this class and to combine somehow this data.
My first approach to this problem was to use a function which accepts as a parameter the std::vector of the class in order to extract the data and return a std:map. The key in this map is the type of the criteria by which the data should be combined and the value is an int with the combined data from all members of this vector.
The problem is that the criteria is not only one - more than one field from this class may be used as criteria (let for easiness all of the criteria are std::string, if they are not - I could make the function templated).
The easiest way for me now is to make dozens of functions with almost identical code and each of them to extract a simple concrete field from this class. However changes might require similar changes to all of the dozens of functions which would be a maintenance headache. But in this stage I cannot think how to pass to a single function a field from this class...
Here's an example code from this class:
// this is the class with data and criteria
class CustomClass
{
public:
std::string criteria1;
std::string criteria2;
std::string criteria3;
//... and others criteria
int dataToBeCombined;
// other code
};
// this is one of these functions
std::map<std::string, int> getDataByCriteria1(std::vector<CustomClass> aVector)
{
std::map<std::string, int> result;
foreach(CustomClass anObject in aVector)
{
if(result.find(anObject.criteria1)==result.end()) // if such of key doesn't exists
{
result.insert(std::make_pair(anObject.criteria1, anObject.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
}
}
return result;
}
and by similar way I should make the other functions which should work with CustomClass::criteria2, CustomClass::criteria3, etc.
I thought to make these criteria in a single array and to pass to this function only the number of the criteria but the class will be used by others for other purposes and the fields must be easy to read, so this will not be an option (i.e. the real names are not criteria1, criteria2, etc. but are descriptive).
Anyone with ideas?
EDIT: Someone referred my question to "C++ same function parameters with different return type" which obviously is very different - the function in my case return the same type every time, just the parameters it takes must be various fields from a class.
You can use pointer to member. Declare an argument std::string CustomClass::*pField in your function, pass it with &CustomClass::criteriaN, access it with anObject.*pField.
See more on the topic: Pointers to data members.
If all "criteria" are of the same type, I don't see an elegant solution but you can "enumerate" they in some way and use their number.
By example, you can declare a templated getVal() method in CustomClass in this way
template <int I>
const std::string & getVal () const;
and implement they, number by number, criteria by criteria, in this way (outside the body of the class)
template <>
const std::string & CustomClass::getVal<1> () const
{ return criteria1; }
template <>
const std::string & CustomClass::getVal<2> () const
{ return criteria2; }
template <>
const std::string & CustomClass::getVal<3> () const
{ return criteria3; }
Now, you can transform getDataByCriteria1() in a templated function getDataByCriteria() in this way
template <int I>
std::map<std::string, int> getDataByCriteria (std::vector<CustomClass> aVector)
{
std::map<std::string, int> result;
for (const auto & cc : aVector)
{
if ( result.find(cc.getVal<I>()) == result.end()) // if such of key doesn't exists
{
result.insert(std::make_pair(cc.getVal<I>(), cc.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
}
}
return result;
}
and call it in this way
auto map1 = getDataByCriteria<1>(ccVec);
auto map2 = getDataByCriteria<2>(ccVec);
auto map3 = getDataByCriteria<3>(ccVec);
--- EDIT: added solution (C++14 only) for different types criteria ---
A little different if the "criteria" are of different types.
The solution work but in C++14, thanks to auto and decltype().
By example, if
std::string criteria1;
int criteria2;
long criteria3;
You can declare getVal() with auto
template <int I>
const auto & getVal () const;
and define (with auto) all versions of getVal()
template <>
const auto & CustomClass::getVal<1> () const
{ return criteria1; }
template <>
const auto & CustomClass::getVal<2> () const
{ return criteria2; }
template <>
const auto & CustomClass::getVal<3> () const
{ return criteria3; }
and combining auto with decltype(), you can modify getDataByCriteria() in this way
template <int I>
auto getDataByCriteria (std::vector<CustomClass> aVector)
{
std::map<decltype(aVector[0].getVal<I>()), int> result;
for (const auto & cc : aVector)
{
if ( result.find(cc.getVal<I>()) == result.end()) // if such of key doesn't exists
{
result.insert(std::make_pair(cc.getVal<I>(), cc.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
}
}
return result;
}
The use of the function remain the same (thanks to auto again)
auto map1 = getDataByCriteria<1>(ccVec);
auto map2 = getDataByCriteria<2>(ccVec);
auto map3 = getDataByCriteria<3>(ccVec);
p.s.: caution: code not tested
p.s.2 : sorry for my bad English
You can use a function to extract a filed such as
std::string extractFiled(const CustomClass &object, int which) {
switch (which) {
case 1:
return object.criteria1;
case 2:
return object.criteria2;
case 3:
return object.criteria3;
default:
return object.criteria1;
}
}
and getDataByCriteria add an arg to indicate which filed to use.
Or you can just use macro to implement getDataByCriteria.
You tagged it C++11, so use variadic templates.
class VariadicTest
{
public:
VariadicTest()
{
std::map<std::string, int> test1 = getDataByCriteria(testValues, criteria1);
std::map<std::string, int> test2 = getDataByCriteria(testValues, criteria2);
std::map<std::string, int> test3 = getDataByCriteria(testValues, criteria1, criteria2);
std::map<std::string, int> test4 = getDataByCriteria(testValues, criteria1, criteria3);
}
private:
std::string criteria1 = { "Hello" };
std::string criteria2 = { "world" };
std::string criteria3 = { "." };
std::vector<CustomClass> testValues = { {"Hello",1}, {"world",2},{ "!",3 } };
template<typename T> std::map<std::string, int> getDataByCriteria(std::vector<CustomClass> values, T criteria)
{
std::map<std::string, int> result;
//do whatever is needed here to filter values
for (auto v : values)
{
if (v.identifier == criteria)
{
result[values[0].identifier] = values[0].value;
}
}
return result;
}
template<typename T, typename... Args> std::map<std::string, int> getDataByCriteria(std::vector<CustomClass> values, T firstCriteria, Args... args)
{
std::map<std::string, int> result = getDataByCriteria(values, firstCriteria);
std::map<std::string, int> trailer = getDataByCriteria(values, args...);
result.insert(trailer.begin(), trailer.end());
return result;
}
};
You do not specify the actual operations to be done under the various conditions of the criteria being met so it is hard to say how much they actually can be combined.
Here is a possible solution using the std::accumulate() of the STL along with some additional functionality. This example was compiled with Visual Studio 2015.
This approach would make sense if most of the functionality can be combined into a reasonably small accumulation function because most of the criteria are handled in the same way. Or you could have the accumulate_op() function call other functions for specific cases while handling the general case itself.
You might take this as a beginning and make the appropriate modifications.
One such modification may be to get rid of the use of std::map to maintain state. Since using this approach you would iterate through the std::vector doing the accumulation based on the criteria, I am not sure you would even need to use std::map to remember anything if you are accumulating as you go.
// map_fold.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <numeric>
// this is the class with data and criteria
class CustomClass
{
public:
CustomClass() : dataToBeCombined(0) {}
std::string criteria1;
std::string criteria2;
std::string criteria3;
//... and others criteria
int dataToBeCombined;
// other code
};
// This is the class that will contain the results as we accumulate across the
// vector of CustomClass items.
class Criteria_Result {
public:
Criteria_Result() : dataToBeCombined(0) {}
CustomClass myCriteria;
std::map<std::string, int> result1;
std::map<std::string, int> result2;
std::map<std::string, int> result3;
int dataToBeCombined;
};
// This is the accumulation function we provide to std::accumulate().
// This function will build our results.
class accumulate_op {
public:
Criteria_Result * operator ()(Criteria_Result * x, CustomClass &item);
};
Criteria_Result * accumulate_op::operator ()(Criteria_Result *result, CustomClass &item)
{
if (!result->myCriteria.criteria1.empty() && !item.criteria1.empty()) {
std::map<std::string, int>::iterator it1 = result->result1.find(item.criteria1);
if (it1 == result->result1.end()) // if such of key doesn't exists
{
result->result1.insert(std::make_pair(item.criteria1, item.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
it1->second += item.dataToBeCombined;
}
result->dataToBeCombined += item.dataToBeCombined;
}
if (!result->myCriteria.criteria2.empty() && !item.criteria2.empty()) {
std::map<std::string, int>::iterator it2 = result->result2.find(item.criteria2);
if (it2 == result->result2.end()) // if such of key doesn't exists
{
result->result2.insert(std::make_pair(item.criteria2, item.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
it2->second += item.dataToBeCombined;
}
result->dataToBeCombined += item.dataToBeCombined;
}
if (!result->myCriteria.criteria3.empty() && !item.criteria3.empty()) {
std::map<std::string, int>::iterator it3 = result->result3.find(item.criteria3);
if (it3 == result->result3.end()) // if such of key doesn't exists
{
result->result3.insert(std::make_pair(item.criteria3, item.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
it3->second += item.dataToBeCombined;
}
result->dataToBeCombined += item.dataToBeCombined;
}
return result;
}
int main()
{
Criteria_Result result;
std::vector<CustomClass> aVector;
// set up the criteria for the search
result.myCriteria.criteria1 = "string1";
result.myCriteria.criteria2 = "string2";
for (int i = 0; i < 10; i++) {
CustomClass xx;
xx.dataToBeCombined = i;
if (i % 2) {
xx.criteria1 = "string";
}
else {
xx.criteria1 = "string1";
}
if (i % 3) {
xx.criteria2 = "string";
}
else {
xx.criteria2 = "string2";
}
aVector.push_back (xx);
}
// fold the vector into our results.
std::accumulate (aVector.begin(), aVector.end(), &result, accumulate_op());
std::cout << "Total Data to be combined " << result.dataToBeCombined << std::endl;
std::cout << " result1 list " << std::endl;
for (auto jj : result.result1) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " result2 list " << std::endl;
for (auto jj : result.result2) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " result3 list " << std::endl;
for (auto jj : result.result3) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " Trial two \n\n" << std::endl;
result.myCriteria.criteria2 = "";
result.result1.clear();
result.result2.clear();
result.result3.clear();
result.dataToBeCombined = 0;
// fold the vector into our results.
std::accumulate(aVector.begin(), aVector.end(), &result, accumulate_op());
std::cout << "Total Data to be combined " << result.dataToBeCombined << std::endl;
std::cout << " result1 list " << std::endl;
for (auto jj : result.result1) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " result2 list " << std::endl;
for (auto jj : result.result2) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " result3 list " << std::endl;
for (auto jj : result.result3) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
return 0;
}
This produces the output as follows:
Total Data to be combined 90
result1 list
string 25
string1 20
result2 list
string 27
string2 18
result3 list
Trial two
Total Data to be combined 45
result1 list
string 25
string1 20
result2 list
result3 list

c++ Unable to resolve overloaded function template

First, I don't understand why the compiler can't seem to resolve the offending code (wrapped by the ENABLE_OFFENDER macro). The two get() methods have very different call signatures. So, perhaps a c++ language lawyer could help explain why I'm getting the error.
Second, is there a way to provide more guidance to the compiler as to which get() it should use?
#include <iostream>
//switch offending code in/out
#define ENABLE_OFFENDER
/// Forward declare
template <typename T> class TableEntry;
/// Non-template base class
class TableEntryBase {
protected:
// prevent instantiation
TableEntryBase() { }
public:
virtual ~TableEntryBase() { }
template <typename T>
void set(const T& rvalue){
TableEntry<T>* entry = dynamic_cast<TableEntry<T> *>(this);
if(0 != entry){
entry->setValue(rvalue);
}
}
template <typename T>
T get(T& lvalue){
TableEntry<T>* entry = dynamic_cast<TableEntry<T> *>(this);
if(0 != entry){
return entry->getValue(lvalue);
} else {
return T();
}
}
template <typename T>
T get(){
TableEntry<T>* entry = dynamic_cast<TableEntry<T> *>(this);
if(0 != entry){
return entry->getValue();
} else {
return T();
}
}
};
template <typename T>
class TableEntry : public TableEntryBase {
private:
T m_value;
public:
TableEntry():TableEntryBase() { }
~TableEntry() { }
void setValue(const T& rvalue){
m_value = rvalue;
}
T getValue(T& lvalue){
lvalue = m_value;
return m_value;
}
T getValue(){
return m_value;
}
};
template <int N>
class Table {
private:
TableEntryBase* m_tableEntries[N];
int m_tableEntriesIndex;
public:
Table():m_tableEntriesIndex(0){}
virtual ~Table() { }
void addEntry(TableEntryBase* entry){
if(0 != entry)
m_tableEntries[m_tableEntriesIndex++] = entry;
}
template <typename T>
void setEntry(int entryIndex, const T& rvalue){
// I'm not sure why it's not set<T>(rvalue)
m_tableEntries[entryIndex]->set(rvalue);
}
template <typename T>
T getEntry(int entryIndex, T& lvalue){
return m_tableEntries[entryIndex]->get(lvalue);
}
#ifdef ENABLE_OFFENDER
template <typename T>
T getEntry(int entryIndex){
return m_tableEntries[entryIndex]->get();
}
#endif
};
int main(){
TableEntry<int> entry1;
// setting the value using base class set
entry1.set<int>(5);
TableEntry<double> entry2;
entry2.set<double>(3.14);
std::cout << "entry1 value = " << entry1.getValue() << std::endl;
std::cout << "entry2 value = " << entry2.getValue() << std::endl;
std::cout << "entry1 value = " << entry1.get<int>() << std::endl;
std::cout << "entry2 value = " << entry2.get<double>() << std::endl;
TableEntryBase* entry_ptr = &entry1;
std::cout << "entry1 value = " << entry_ptr->get<int>() << std::endl;
Table<2> table;
table.addEntry(&entry1);
table.addEntry(&entry2);
table.setEntry<int>(0, 10);
std::cout << "entry1 value = " << entry1.get<int>() << std::endl;
std::cout << "entry2 value = " << entry2.get<double>() << std::endl;
int val3 = 0;
int val4 = 0;
val4 = table.getEntry<int>(0, val3);
int val5 = 0;
#ifdef ENABLE_OFFENDER
val5 = table.getEntry<int>(0);
#endif
std::cout << "val3 = " << val3 << ", val4 = " << val4 << ", val5 = " << val5 << std::endl;
return 0;
}
/* GCC error
main.cpp:129:30: instantiated from here
main.cpp:96:95: error: no matching function for call to ‘TableEntryBase::get()’
main.cpp:96:95: note: candidates are:
main.cpp:26:4: note: template<class T> T TableEntryBase::get(T&)
main.cpp:36:4: note: template<class T> T TableEntryBase::get()
*/
I got the code to work on my older compilers by changing the offending code as such.
#ifdef ENABLE_OFFENDER
template <typename T>
T getEntry(int entryIndex){
// Error: expected primary-expression before ‘>’ token
//return m_tableEntries[entryIndex]->get<T>();
// Error: couldn't deduce template parameter ‘T’
//return m_tableEntries[entryIndex]->get();
TableEntryBase* entry = m_tableEntries[entryIndex];
return entry->get<T>();
}
#endif

Boost Fibonacci Heap

I was looking at the code of the boost Fibonacci heap, and in many places, I saw a variable called _id of type ID (part of the template) being used like this:get(_id, d), where d is of type T&, where T is part of the template. What is the purpose of this, and what would the equivalent of this be with only the default c++ standard libraries.
Here is the code for the fibonacci heap:
void push(const T& d) {
++_n;
size_type v = get(_id, d);
_key[v] = d;
_p[v] = nil();
_degree[v] = 0;
_mark[v] = false;
_child[v] = nil();
if (_root == nil()) {
_root = _left[v] = _right[v] = v;
//std::cout << "root added" << std::endl;
} else {
size_type u = _left[_root];
_left[v] = u;
_right[v] = _root;
_left[_root] = _right[u] = v;
if (_compare(d, _key[_root]))
_root = v;
//std::cout << "non-root node added" << std::endl;
}
}

Object values altered after return from function

PART OF A HOMEWORK PROBLEM
I have a list of objects, and my goal is to try and find if an object X is present in that list (I am interested only in the first occurrence of that object). My code seems to work fine for the most part, but I have this strange error where the value of only 1 particular object is being modified after it is returned from a function.
I added 10 objects to the list with values 0 through 3. When I search for any number except 0, (./a.out 1 OR ./a.out 2 and so on)I get the right output. But when I search for 0(./a.out 0), the findInList() prints the correct result, but the main() prints the value 18 (which is not even present in the list).
I am attaching the full source code here in case someone wants to compile it and try it out. I am also attaching the gdb step through I did.
SOURCE:
#include <iostream>
#include <string>
#include <functional>
#include <list>
using namespace std;
class Page {
public:
int pgnum; // page number
union {
int lfu_count;
int lru_clock:1; // can only be 0/1
int lru_ref8:8; // we only need 8 bits
};
public:
// Constructors
Page(int num) { pgnum = num; }
Page() {}
// Operator overloading
bool operator== (const Page &p) const {
if(p.pgnum == pgnum)
return true;
else
return false;
}
bool operator!= (const Page &p) const {
return !(p==*this);
}
};
ostream & operator<<(ostream & os, const Page &p) {
os << "Page number: " << p.pgnum;
return os;
}
// Think of this as an equivalent to equals in Java (IT IS NOT, JUST IMAGINE)
struct PageNumber: public binary_function< Page, Page, bool > {
bool operator () ( const Page &p1, const Page &p2 ) const {
return p1 == p2;
}
};
// Function to find an object in any list given an Operation
template <class Operation, class T>
T* findInList( list<T> fullList, T obj, const Operation &op ) {
T* ret = NULL;
typename list<T>::iterator it = fullList.begin();
it = find_if( it, fullList.end(), bind2nd( op, obj ) );
if( it != fullList.end() ) {
cout << "Found obj in list: " << *it << endl;
ret = &(*it); // not the same as it (which is of type iterator)
}
return ret;
}
int main( int argc, char **argv ) {
Page page_to_find;
list<Page> frames;
if( argc != 2 ) {
cout << "Please enter 1 and only 1 argument" << endl;
exit(-1);
}
page_to_find.pgnum = atoi(argv[1]);
Page *p = new Page[10];
for( int i=0; i<10; i++ ) {
p[i].pgnum = i%4;
frames.push_back(p[i]);
}
list<Page>::iterator it_frames = frames.begin();
while( it_frames != frames.end() ) {
cout << "Page in frames: " << *it_frames << endl;
it_frames++;
}
Page* pg = findInList( frames, page_to_find, PageNumber() );
if( pg != NULL )
cout << "Found page: " << *pg << endl;
delete[] p;
return 0;
}
You're returning the address of an object in a list that is pushed into the parameter list by value. Thus it is undefined behavior. Consider changing the parameter of the list in findInList to a reference.
// note reference type change in parameter list.
template <class Operation, class T>
T* findInList( list<T>& fullList, T obj, const Operation &op ) {
T* ret = NULL;
typename list<T>::iterator it = fullList.begin();
it = find_if( it, fullList.end(), bind2nd( op, obj ) );
if( it != fullList.end() ) {
cout << "Found obj in list: " << *it << endl;
ret = &(*it); // not the same as it (which is of type iterator)
}
return ret;
}