I need to use a function template which is available in a header file via a function pointer which is available as a struct member.
For example:
File: mytemplate.h
template<typename T> const bool GT(const T& pa_roIN1, const T& pa_roIN2)
{
bool temp = false;
if(pa_roIN1 > pa_roIN2){
temp = true;
}
return temp;
}
template<typename T> const bool EQ(const T& pa_roIN1, const T& pa_roIN2)
{
bool temp = false;
if(pa_roIN1 == pa_roIN2){
temp = true;
}
return temp;
}
template<typename T> const bool GE(const T& pa_roIN1, const T& pa_roIN2)
{
bool temp = false;
if(pa_roIN1 >= pa_roIN2){
temp = true;
}
return temp;
}
File: mystruct.h:
struct mystruct {
std::string funcName;
bool (*funcPtr)(int,int);
};
typedef std::map<int, mystruct> mystructList;
File: mycpp.cpp:
#include "mytemplate.h"
#include "mystruct.h"
mystruct MyGreaterStruct[3] = {
{"GREATER_THAN", >},
{ "EQUAL", &EQ},
{ "GREATER_N_EQUAL", &GE}
};
mystructList MyList;
int main(void)
{
int size = sizeof(MyGreaterStruct)/sizeof(mystruct);
for(int i = 0; i < size; i++) {
MyList.insert(std::pair<int, mystruct>(i,MyGreaterStruct[i])); }
for(mystructList::iterator iter = MyList.begin(); iter != MyList.end(); iter++) {
printf("\nResult of func : %s for values 100,50 : %d",iter->second.funcName.c_Str(),iter->second->funcPtr(100,50));
}
}
I am not sure this the correct way of doing it. But there is no result that gets printed on the console.
The error you get when compiling your code tells you what is wrong:
mycpp.cpp:8:1: error: no matches converting function ‘GT’ to type ‘bool (*)(int, int)’
};
^
mytemplate.h:1:33: note: candidate is: template<class T> const bool GT(const T&, const T&)
template<typename T> const bool GT(const T& pa_roIN1, const T& pa_roIN2)
^
There's no way to instantiate that template to match the signature of the function pointer, as the template takes two references as arguments, while the pointer takes two ints. If you can't change either the struct or the templates, and you are using C++11, you could try using lambdas instead:
mystruct MyGreaterStruct[3] = {
{"GREATER_THAN", [](int a, int b)->bool { return GT(a, b); } },
{ "EQUAL", [](int a, int b)->bool { return EQ(a, b); } },
{ "GREATER_N_EQUAL", [](int a, int b)->bool { return GE(a, b); } }
};
but no matter how you slice it, you need to either change the arguments or use a little function that converts the arguments from one form to the other.
Related
I have a simple reverse comparer defined as follows:
template <class T, class Compare>
class ReverseCompare
{
public:
//The same as Container::value_type, for example std::shared_ptr<A>.
using value_type = T;
//The type of the key for heterogeneous lookup.
using key_type = typename Compare::key_type;
ReverseCompare(Compare comp = Compare()) : m_comp(std::move(comp))
{
}
constexpr bool operator()(const T& left, const T& right) const
{
return m_comp(right, left);
}
constexpr bool operator()(const T& val, const key_type& id) const
{
return m_comp(id, val);
}
constexpr bool operator()(const key_type& id, const T& val) const
{
return m_comp(val, id);
}
using is_transparent = void;
private:
Compare m_comp;
};
template <class T, class Compare>
ReverseCompare<T, Compare> reverse_comparer(Compare comp)
{
return ReverseCompare<T, Compare>(std::move(comp));
}
it assumes that its underlying comparer is transparent like this:
struct Comparator
{
using is_transparent = std::true_type;
bool operator()(const sw& lhs, const std::string& rhs) const { return lhs.getString() < rhs; }
bool operator()(const std::string& lhs, const sw& rhs) const { return lhs < rhs.getString(); }
bool operator()(const sw& lhs, const sw& rhs) const { return lhs < rhs; }
};
but it would not compile if the underlying comparer is a simple lambda, for example:
void main()
{
auto comp = [](const int& left, const int& right) -> bool
{
return left < right;
};
auto r_comp = reverse_comparer<int>(comp);
return 1;
}
GCC error message:
prog.cc: In instantiation of 'class ReverseCompare<int, main()::<lambda(const int&, const int&)> >':
prog.cc:53:36: required from here
prog.cc:12:11: error: no type named 'key_type' in 'struct main()::<lambda(const int&, const int&)>'
12 | using key_type = typename Compare::key_type;
| ^~~~~~~~
what is the right way to fix this?
Should I define a separate class or there is a better way?
EDIT1
I need key_type because I have CompositeCompare that requires it:
template <class T, class ... Cs>
class CompositeCompare
{
public:
//The same as Container::value_type, for example std::shared_ptr<A>.
using value_type = T;
//The type of the key for heterogeneous lookup.
using key_type = std::tuple<typename std::decay_t<Cs>::key_type...>;
//Can be used if all the comparers are default constructible.
CompositeCompare() = default;
//A template parameter pack cannot have a default argument.
CompositeCompare(Cs... comp) : m_comps(std::move(comp) ...)
{
}
constexpr bool operator()(const T& left, const T& right) const
{
return Compare<0u>(left, right);
}
constexpr bool operator()(const T& val, const key_type& id) const
{
return Compare<0u>(val, id);
}
constexpr bool operator()(const key_type& id, const T& val) const
{
return Compare<0u>(id, val);
}
using is_transparent = void;
private:
using Tuple = std::tuple<std::decay_t<Cs>...>;
template <std::size_t Index>
bool Compare(const T& left, const T& right) const
{
if constexpr (Index == std::tuple_size_v<Tuple>)
{
static_cast<void>(left);
static_cast<void>(right);
return false;
}
else
{
auto& comp = std::get<Index>(m_comps);
if (comp(left, right))
{
return true;
}
if (comp(right, left))
{
return false;
}
return Compare<Index + 1>(left, right);
}
}
template <std::size_t Index>
bool Compare(const T& left, const key_type& right_key) const
{
if constexpr (Index == std::tuple_size_v<Tuple>)
{
static_cast<void>(left);
static_cast<void>(right_key);
return false;
}
else
{
auto& comp = std::get<Index>(m_comps);
auto right = std::get<Index>(right_key);
if (comp(left, right))
{
return true;
}
if (comp(right, left))
{
return false;
}
return Compare<Index + 1>(left, right_key);
}
}
template <std::size_t Index>
bool Compare(const key_type& left_key, const T& right) const
{
if constexpr (Index == std::tuple_size_v<Tuple>)
{
static_cast<void>(left_key);
static_cast<void>(right);
return false;
}
else
{
auto& comp = std::get<Index>(m_comps);
auto left = std::get<Index>(left_key);
if (comp(left, right))
{
return true;
}
if (comp(right, left))
{
return false;
}
return Compare<Index + 1>(left_key, right);
}
}
Tuple m_comps;
};
template <class T, class ... Cs>
CompositeCompare<T, Cs ...> compose_comparers(Cs... comp)
{
return CompositeCompare<T, Cs ...>(std::move(comp) ...);
}
CompositeCompare assumes all its underlying comparers are transparent, and if they are not it ideally should not be transparent. Its usage:
struct X
{
int a;
std::string b;
};
using ACompare = ...
using BCompare = ...
auto comp = compose_comparers<X>(ACompare(), BCompare());
Take a look at this implementation of a linked list:
#include <memory>
#include <type_traits>
#include <iostream>
using namespace std;
template<typename D>
class List {
struct Node {
shared_ptr<D> data;
Node* next;
Node(shared_ptr<D> d, Node* p, Node* n) : data(d), next(n) {}
~Node() {
data.reset();
delete next;
}
};
template <bool isconst = false>
struct iterator : public std::iterator<std::forward_iterator_tag, shared_ptr<D>> {
typedef std::forward_iterator_tag iterator_category;
typedef shared_ptr<D> value_type;
typedef std::ptrdiff_t Distance;
typedef typename conditional<isconst, const value_type&, value_type&>::type
Reference;
typedef typename conditional<isconst, const value_type*, value_type*>::type
Pointer;
typedef typename conditional<isconst, const Node*, Node*>::type
nodeptr;
iterator(nodeptr x = nullptr) : curr_node(x) {}
iterator(const iterator<false>& i) : curr_node(i.curr_node) {}
Reference operator*() const { return curr_node->data; }
Pointer operator->() const { return &(curr_node->data); }
template<bool A>
friend bool operator==(const iterator<A>& a, const iterator<A>& b) {
return a.curr_node == b.curr_node;
}
template<bool A>
friend bool operator!=(const iterator<A>& a, const iterator<A>& b) {
return !(a.curr_node == b.curr_node);
}
friend class List<D>;
iterator& operator++() {
curr_node = curr_node->next;
return *this;
}
private:
nodeptr curr_node;
};
public:
List() {
head = nullptr;
}
int len() const {
int ret = 0;
for (const auto& n : *this) {
ret++;
}
return ret;
}
~List() {
delete head;
}
std::ostream& dump(std::ostream &strm) const {
for (const auto s : *this) {
strm << *s << std::endl;
}
return strm;
}
iterator<false> begin() {
return iterator<false>(head);
}
iterator<false> end() {
return iterator<false>(nullptr);
}
iterator<true> begin() const {
return iterator<true>(head);
}
iterator<true> end() const {
return iterator<true>(nullptr);
}
private:
Node* head;
};
The part giving me problems is the iterator implementation for this list. The iterator template is supposed to provide both mutable and const iterators.
This is a program which uses this implementation:
#include "List.h"
#include <iostream>
int main( int argc, const char *argv[] ) {
List<int> l;
std::cout << l.len() << std::endl;
return 0;
}
The program compiles and runs fine if I use clang++, but the compilation fails for g++ with the following error:
In file included from t.cpp:1:
List.h: In instantiation of ‘struct List<int>::iterator<false>’:
List.h:136:5: required from ‘int List<D>::len() const [with D = int]’
t.cpp:7:24: required from here
List.h:64:21: error: redefinition of ‘template<bool A> bool operator==(const List<int>::iterator<isconst>&, const List<int>::iterator<isconst>&)’
friend bool operator==(const iterator<A>& a, const iterator<A>& b) {
^~~~~~~~
List.h:64:21: note: ‘template<bool A> bool operator==(const List<int>::iterator<isconst>&, const List<int>::iterator<isconst>&)’ previously declared here
List.h:69:21: error: redefinition of ‘template<bool A> bool operator!=(const List<int>::iterator<isconst>&, const List<int>::iterator<isconst>&)’
friend bool operator!=(const iterator<A>& a, const iterator<A>& b) {
^~~~~~~~
List.h:69:21: note: ‘template<bool A> bool operator!=(const List<int>::iterator<isconst>&, const List<int>::iterator<isconst>&)’ previously declared here
What's the cause of this error? How can I fix this?
The problem seems to be here:
template <bool isconst = false>
struct iterator : public std::iterator<std::forward_iterator_tag, shared_ptr<D>> {
template<bool A>
friend bool operator==(const iterator<A>& a, const iterator<A>& b) {
return a.curr_node == b.curr_node;
}
This is saying: For all values of isconst (the outer template parameter), define a template function template<bool A> bool operator==.
So instantiating iterator<true> will define template<bool A> bool operator==, and then instantiating iterator<false> will define template<bool A> bool operator== again, causing a redefinition error.
Solution: Remove the inner template. Have each instantiation of iterator only define its own operator==:
template <bool isconst = false>
struct iterator : public std::iterator<std::forward_iterator_tag, shared_ptr<D>> {
friend bool operator==(const iterator& a, const iterator& b) {
return a.curr_node == b.curr_node;
}
(Here iterator automatically refers to iterator<isconst>, i.e. the current instantiation.)
I'm trying to implement a template class that wraps around a
STL container of pointers, as in:
tContainer_t<T, vector<T*> >
or
tContainer_t<T, list<T*> >
Here's the class declaration:
template <typename T, typename Container>
class tContainer_t
{
public:
tContainer_t() {} //Default CTOR
~tContainer_t() {} //DTOR
bool IsEmpty() const;
size_t Size() const;
bool Insert(T* _element);
T* Find(T _value);
T* Remove(T _value);
T* operator[](size_t _index);
private:
tContainer_t(const tContainer_t& _other); //Disable Copy
Container m_container;
};
I want to practice different implementations for operator[] (for vector and list),so I wrote:
template <typename T, typename Container>
T* tContainer_t<T, Container>::operator[](size_t _index)
{
T* retval;
if (_index > m_container.size())
{
return 0;
}
if (typeid(m_container) == typeid(vector<T*>))
{
retval = m_container[_index];
}
if (typeid(m_container) == typeid(list<T*>))
{
typename Container::iterator contIter = m_container.begin();
advance(contIter, _index);
retval = *contIter;
}
return retval;
}
and I get strange behavior. when I use a vector in main, the code works fine. When I use a list, it doesn't even compile, showing:
container.h: In instantiation of ‘T* tContainer_t<T, Container>::operator[](size_t) [with T = int; Container = std::list<int*>; size_t = long unsigned int]’:
container.cpp:10:14: required from here
container.h:141:23: error: no match for ‘operator[]’ (operand types are ‘std::list<int*>’ and ‘size_t {aka long unsigned int}’)
retval = m_container[_index];
Here's how I'm using it:
int main(int argc, char const *argv[])
{
tContainer_t<int, list<int*> > a;
int i = 5;
a.Insert(&i);
cout << *a[0] << endl;
return 0;
}
All the code in a function will get compiled, regardless of whether or not it'll ever get run. So this:
if (typeid(m_container) == typeid(vector<T*>))
{
retval = m_container[_index];
}
cannot possibly ever work for list<T>, since list has no operator[]. Hence the compiler error. It doesn't matter that it won't get run, it still has to compile. The way to do this instead is to dispatch to different functions based on the type of m_container:
template <typename T, typename Container>
T* tContainer_t<T, Container>::operator[](size_t _index)
{
if (_index > m_container.size())
{
return 0;
}
return _get_index(m_container, _index);
}
With a vector version:
template <class T>
T* tContainer_t<T, Container>::_get_index(std::vector<T*>& v, size_t _index) {
return v[_index];
}
And a list version:
template <class T>
T* tContainer_t<T, Container>::_get_index(std::list<T*>& lst, size_t _index)
{
typename Container::iterator contIter = lst.begin();
advance(contIter, _index);
return *contIter;
}
At least that's a good general approach. In this case, we don't actually have to split them up, since we can use advance() for both container types. It'll be cheap for the vector and expensive for list:
template <typename T, typename Container>
T* tContainer_t<T, Container>::operator[](size_t _index)
{
if (_index >= m_container.size()) // note the off-by-one error I fixed here
{
return nullptr;
}
auto it = m_container.begin();
std::advance(it, _index);
return *it;
}
Or simply:
return *std::next(m_container.begin(), _index);
I am working on operator overloading to generate lazy object evaluation. For this reason class at operator+() doesn’t do more than storing reference of passed classes to evaluate later.
struct Base
{
virtual void expensive_func()
{
throw "cant use this";
};
Composer operator+(int i)
{
return Composer(*this, i);
}
}
struct Composer:public Base
{
Base& refBase;
int increment;
virtual void expensive_func()
{
heavy_work();
};
Composer(Base& a,int inc):
refBase(a),increment(inc)
{
}
}
struct D:public Base
{
...
}
And than problem arase
D a;
auto b = a + 2;
auto c = b + 3;
auto e = a + 3 + 4;
a.expensive_func(); //fine
b.expensive_func(); //fine
c.expensive_func(); //fine
e.expensive_func(); //segfault
On solution is to prevent such manoeuvres with
operator+(const Coposer&&,int) = delete;
But this just prevents doing something of what I would like to do
Full code: - I am building with gcc/g++ 4.8
#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>
#include <memory>
namespace Intervals
{
template <typename T> struct ContainerMove; //forward declaration
template <typename T>
struct ContainerBase {
typedef T mT;
virtual T GetInterval (const T& val)
{
throw; //overload this
}
T Integrate(const T& start = T(0))
{
T r(0);
T next(start);
while(1)
{
T i = GetInterval(next);
if(i<0) //less that 0 is considered end
{
return r;
}
r+=i;
next=i;
}
}
ContainerMove<T> operator +(const T& left);
ContainerMove<T> operator -(const T& left);
virtual ~ContainerBase(){};
};
//lazy container of ContainerBase
template <typename T>
struct ContainerMove:public ContainerBase<T>
{
typedef ContainerBase<T> mConatinerBase;
const T mOffset;
mConatinerBase& mIntervalSet;
ContainerMove(mConatinerBase& intervalset, const T& offset)
:mOffset(offset),mIntervalSet(intervalset)
{}
virtual T GetInterval (const T& val)
{
auto i = mIntervalSet.GetInterval(val-mOffset);
if(i < 0)
{
return T(-1000);
}
return T(i+mOffset);
}
};
template <typename T>
ContainerMove<T> ContainerBase<T>::operator +(const ContainerBase<T>::mT& a)
{
return ContainerMove<T>(*this,a);
}
template <typename T>
ContainerMove<T> ContainerBase<T>::operator -(const ContainerBase<T>::mT& a)
{
return ContainerMove<T>(*this,-a);
}
/*
template <typename T>
ContainerMove<T> operator +(const ContainerMove<T>&& , const typename ContainerBase<T>::mT&) = delete;
template <typename T>
ContainerMove<T> operator -(const ContainerMove<T>&& , const typename ContainerBase<T>::mT&) = delete;
*/
template <class T>
struct Container:public ContainerBase<T>
{
typedef Container<T> mThisType;
typedef T mT;
typedef std::vector<T> SortedContainer_t;
SortedContainer_t mContainer;
template<class ForwardIter>
Container(ForwardIter begin,ForwardIter end)
:mContainer(begin,end)
{
}
T GetInterval (const T& val)
{
auto r = std::upper_bound(mContainer.begin(), mContainer.end(),val);
if (r == mContainer.end())
{
return T(-1000); //just as exeample <0 is ivalid value
}
return *r;
}
};
}
int main()
{
typedef float T;
typedef Intervals::Container<T> ContainerType;
std::vector<T> v,u;
const int N = 10;
for(int i=0;i<N;++i)
{
v.push_back(T(i));
}
auto c = ContainerType(v.begin(),v.end());
auto d=c+T(1);
auto e=c+T(2)+T(3); //this yelds segmentation after e.Integrate()
//std::cout << c.Integrate() << std::endl;
//std::cout << d.Integrate() << std::endl;
std::cout << e.Integrate() << std::endl; //crash here
return 0;
}
Due to some legacy reasons I'm stuck with MIPS-GCC 4.5.3. But the code which I'm trying to compile uses C++11 nullptr & nullptr_t heavily which is a missing feature in GCC 4.5.3.
After some googling & getting into the usage I ended up creating a nullptr wrapper like below, but unfortunately it doesn't satisfy some of the use case,
namespace std {
class nullptr_t {
public:
nullptr_t() { }
template <typename T> nullptr_t(const T&) { }
template <class T> nullptr_t(const T*) { }
template <class T> nullptr_t(T*) { }
template <typename T, typename U> nullptr_t(const typename T::U*) { }
template<typename T> operator T*() { return 0;}
template<typename T1, typename T2> operator T1 T2::*() { return 0; }
operator int() const { return 0; }
operator unsigned() const { return 0; }
operator bool() const { return false; }
bool operator == (unsigned i) const { return i == 0; }
bool operator != (unsigned i) const { return i != 0; }
bool operator !() const { return true; }
} nullptr = {};
}
using std::nullptr;
template<typename T> struct DummyContainer {
DummyContainer(T* ptr)
: m_ptr(ptr) { }
DummyContainer(std::nullptr_t)
: m_ptr(0) { }
T& operator = (std::nullptr_t) { return *m_ptr; }
private: T* m_ptr;
};
int main(int argc, char** argv)
{
const char* case1 = nullptr; // working
// I think for below case std::unique_ptr has to be modified to take std::nullptr_t during construction & operator =
std::unique_ptr<char> case2 = nullptr; // not working.
DummyContainer<char> case3 = nullptr; // working
case3 = nullptr; //working
unsigned* case4 = argc > 1 ? nullptr : nullptr; //works
unsigned* case5 = argc > 2 ? (unsigned*)0 : nullptr; //not working. (It is the major issue as of now)
return 0;
}
Here the major case is unsigned* case5 = argc > 2 ? (unsigned*)0 : nullptr;
IDEONE snapshot : http://ideone.com/m1mhtB
(Thanks to http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf)
Any tips/suggestions will be appreciated :)
(Note: please avoid answers like upgrade your gcc)
Below solution seems to be working,
Original source: https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/wtf/NullPtr.h
namespace std {
class nullptr_t {
public:
// Required in order to create const nullptr_t objects without an
// explicit initializer in GCC 4.5, a la:
//
// const std::nullptr_t nullptr;
nullptr_t() { }
// Make nullptr convertible to any pointer type.
template<typename T> operator T*() const { return 0; }
// Make nullptr convertible to any member pointer type.
template<typename C, typename T> operator T C::*() { return 0; }
private:
// Do not allow taking the address of nullptr.
void operator&();
};
}
const std::nullptr_t nullptr;
IDEOne: http://ideone.com/Bnp6th