Boost Hana provides the ability to introspect on class member fields in a simple and beautiful way:
// define:
struct Person {
std::string name;
int age;
};
// below could be done inline, but I prefer not polluting the
// declaration of the struct
BOOST_HANA_ADAPT_STRUCT(not_my_namespace::Person, name, age);
// then:
Person john{"John", 30};
hana::for_each(john, [](auto pair) {
std::cout << hana::to<char const*>(hana::first(pair)) << ": "
<< hana::second(pair) << std::endl;
});
However, the documentation only mentions member fields. I would like to introspect on methods also. I've tried to naively extend the example with a method:
struct Foo {
std::string get_name() const { return "louis"; }
};
BOOST_HANA_ADAPT_STRUCT(::Foo, get_name);
This compiles. However, as soon as I try to use it, using code similar to the above (for_each...), I get many compile errors. Since there are no examples that show introspection of methods, I'm wondering whether it is supported.
My original answer was crap; sorry for that. Here's a rewrite that actually answers the question.
I just added a macro to allow easily defining a Struct with custom accessors. Here's how you could do it:
#include <boost/hana/adapt_adt.hpp>
#include <boost/hana/at_key.hpp>
#include <boost/hana/string.hpp>
#include <cassert>
#include <string>
namespace hana = boost::hana;
struct Person {
Person(std::string const& name, int age) : name_(name), age_(age) { }
std::string const& get_name() const { return name_; }
int get_age() const { return age_; }
private:
std::string name_;
int age_;
};
BOOST_HANA_ADAPT_ADT(Person,
(name, [](auto const& p) { return p.get_name(); }),
(age, [](auto const& p) { return p.get_age(); })
);
int main() {
Person bob{"Bob", 30};
assert(hana::at_key(bob, BOOST_HANA_STRING("name")) == "Bob");
assert(hana::at_key(bob, BOOST_HANA_STRING("age")) == 30);
}
That code should work on master. Otherwise, if you need more control over the definition of your accessors or the keys used to map to them, you can also define the whole thing by hand:
namespace boost { namespace hana {
template <>
struct accessors_impl<Person> {
static auto apply() {
return hana::make_tuple(
hana::make_pair(BOOST_HANA_STRING("name"), [](auto&& p) -> std::string const& {
return p.get_name();
}),
hana::make_pair(BOOST_HANA_STRING("age"), [](auto&& p) {
return p.get_age();
})
);
}
};
}}
You can find more information about how to define Structs in the reference for the Struct concept.
Related
struct compare{
string k;
compare(string a) : k(a){}
bool operator()(const product* t)const{
return (t->productdetails.getName()<k);
}
};
void cashier::calculate(string s,vector<product*> &a){
//this is lambda (tried to use it ,but doesn't work)
auto comp=[](const product* t, const string b)
{
return (b < t->productdetail.getName());
};
if (std::binary_search ( a.begin(), a.end(),s, compare(s)))
cout << "found!\n";
else
std::cout << "not found.\n";
}
I'm stuck in this part for a long time.
the vector holds product(class) pointer. product pointer points to productdetail which has two variables (name and price)
I need to look up (string s) in the vector and if the string s is in vector (product->productdetail.getName()), I need to return the price..
how to compare proudct* and string s ?
my teacher gave me advice that i need to make anther string conversion function since the comparing type need to be the same..
(I tried to use lambda and it didn't work and changed to compare function)
I concur with #Fureeish, using bare pointers in modern C++ is not a good choice, unless you absolutely have to.
That said, writing predicates for the standard library requires a good knowledge of the library methods you are using. Have a look at std::binary_search documentation. A simple application is to search for the same type as you are searching through. In other words your needle is the same type as what is in your haystack. Here is an example:
#include <iostream>
#include <vector>
#include <algorithm>
class product {
public:
class product_details {
public:
std::string name;
double price;
};
product_details productDetails{};
product(std::string const &name, double price) : productDetails{ name, price} {}
};
struct product_compare {
bool operator()(product const &lhs, product const &rhs) {
return lhs.productDetails.name < rhs.productDetails.name;
}
};
int main(int argc, char *argv[])
{
std::vector<product> producList{
{ "toaster", 74.99 },
{ "blender", 103.99 },
{ "slow cooker", 142.99 }
};
product_compare productCompare{};
std::sort(producList.begin(), producList.end(), productCompare);
product searchProduct{"slow cooker", 142.99};
if (std::binary_search(producList.begin(), producList.end(), searchProduct, productCompare))
std::cout << "Found!\n";
else
std::cout << "Not found!\n";
}
But that lacks elegance. Your needle can be a different type, the answer is actually in this SO question. Here is a rewrite that takes advantage of this. This idiom is a bit more complicated to write but is better related to the actual problem and therefore easier to understand. Ultimately you never know which side of the compare is going to be needle and which side is going to be hay. So you have to write your compare predicate to accept both comparisons.
#include <iostream>
#include <vector>
#include <algorithm>
class product {
public:
class product_details {
public:
std::string name;
double price;
};
product_details productDetails{};
product(std::string const &name, double price) : productDetails{ name, price} {}
};
struct product_compare {
bool operator()(std::string const &lhs, product const &rhs) {
return lhs < rhs.productDetails.name;
}
bool operator()(product const &lhs, std::string const &rhs ) {
return lhs.productDetails.name < rhs;
}
};
// Used by std::sort
bool operator<(product const &lhs, product const &rhs) {
return lhs.productDetails.name < rhs.productDetails.name;
}
int main(int argc, char *argv[])
{
std::vector<product> producList{
{ "toaster", 74.99 },
{ "blender", 103.99 },
{ "slow cooker", 142.99 }
};
product_compare productCompare{};
std::sort(producList.begin(), producList.end());
if (std::binary_search(producList.begin(), producList.end(), std::string("slow cooker"), productCompare))
std::cout << "Found!\n";
else
std::cout << "Not found!\n";
}
I am implementing an object that makes use of unordered_map. The object is to be generic, so templates everywhere. In particular the operator== and operator() are wrapped into structures that are used by the unordered_map to respectively check if keys are equal and to generate hash values for keys. I'd like the user to write their own functions that implement the above two operators and pass those methods as input to the class object. The structs would then use those objects. I'm having some trouble with scopes and can't seem to figure out how to do it. Here's my code:
#include <unordered_map>
#include <iostream>
#include <string>
#include <functional>
template <typename O>
class aClass
{
public:
aClass( bool (usrIsEq)(O, O) ,
std::size_t (usrHashFtn)(O) )
{
this->usrIsEq = usrIsEq;
this->usrHashFtn = usrHashFtn;
}
void add(O k, std::string v)
{
iTable[ {k} ] = v;
}
std::string get(O k)
{
return iTable[ {k} ];
}
private:
bool (*usrIsEq)(O, O);
std::size_t (*usrHashFtn)(O);
struct Key
{
O obj;
bool operator==(const Key &other) const
{
std::cout << "obj " << obj << std::endl;
return usrIsEq(obj, other.obj);
}
};
struct KeyHasher
{
std::size_t operator()(const Key &k) const
{
return usrHashFtn(k);
}
};
std::unordered_map<Key, std::string, KeyHasher> iTable;
};
bool isEqInts(int a, int b)
{
return a == b;
}
std::size_t intHashFtn(int x)
{
std::hash<int> hf;
return hf(x);
}
int main()
{
aClass<int> x(isEqInts, intHashFtn);
x.add( 1, std::string("hello") );
}
I'm not entirely sure how to implement the structs Key and KeyHasher so that they use the functions contained inside the class. The only thing I truly care about is that the functions are given as input to the class constructor. Everything else can be scrapped.
The main problem that's tripping you up is that Key has no knowledge usrIsEq and KeyHasher has no knowledge of usrHashFtn. You need to pass a pointer or reference to an object of aClass to those classes.
Here' one suggestion:
struct Key
{
O obj;
aClass* ac;
bool operator==(const Key &other) const
{
std::cout << "obj " << obj << std::endl;
return ac->usrIsEq(obj, other.obj);
}
};
struct KeyHasher
{
std::size_t operator()(const Key &k) const
{
return k.ac->usrHashFtn(k.obj);
}
};
and update the places where you use Key to access the table:
void add(O k, std::string v)
{
iTable[{k, this}] = v;
}
std::string get(O k)
{
return iTable[{k, this}];
}
I am trying to create template classes for some repetitive functions that will be required for sending data around, of different types. However, my issue (I think) is really with InterfacePublisher::addSubscription() function that is utilizing boost::signals2::signal::connect().
It seems like connect function is taking the location of the base classes, even though derived classes override them. I am sure there is going to be a fix for this but am stuck with it for a long while now.
I am pasting my code below. The idea is to pass a string from StringPublisher to StringSubscriber without hard-coding the class names through the templates:
#include <string>
#include <iostream>
#include <boost/lambda/lambda.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/signals2/signal_base.hpp>
#include <boost/signals2/slot.hpp>
#include <boost/signals2/slot_base.hpp>
template <class T>
class InterfaceSubscriber
{
public:
InterfaceSubscriber(const std::string& name)
: mName (name) {}
virtual void onData (const std::string& source, T& data)
{
std::cout << "InterfaceSubscriber::onData::BASE SHOULD BE IGNORED\n";
}
protected:
const std::string mName;
};
template <class T>
class InterfacePublisher
{
public:
InterfacePublisher(const std::string& publisherName)
: mPublisherName (publisherName)
{
}
void publish(T& data)
{
mSignalArgs(mPublisherName, data);
}
void addSubscription (InterfaceSubscriber<T>* subsc)
{
// The section where I think problem is. There is where the solution should be
mSignalArgs.connect( std::bind (InterfaceSubscriber<T>::onData , *subsc, std::placeholders::_1, std::placeholders::_2) );
}
protected:
boost::signals2::signal<void (const std::string& publisherName, T& data)> mSignalArgs;
const std::string mPublisherName;
};
class StringSubscriber : public InterfaceSubscriber<std::string>
{
public:
StringSubscriber (const std::string& subscName) : InterfaceSubscriber(subscName) {}
void onData (const std::string& source, std::string& data) override
{
std::cout << mName << ":[" << source << "]Received string of value: " << data << std::endl;
}
};
class StringPublisher : public InterfacePublisher<std::string>
{
public:
StringPublisher (const std::string& name) : InterfacePublisher(name) {}
};
int main()
{
StringSubscriber subscriber1("String_Subscriber_1");
StringSubscriber subscriber2("String_Subscriber_2");
StringPublisher publisher("Publisher_Of_String");
publisher.addSubscription(&subscriber1);
publisher.addSubscription(&subscriber2);
std::string str = "Hello World";
// This should lead to StringSubscriber::onData being called, but instead ends up calling InterfaceSubscriber<T>::onData
publisher.publish(str);
}
StringSubscriber is being sliced during the construction of the std::bind functor, resulting in InterfaceSubscriber<T>::onData() executing on an object with a runtime type of InterfaceSubscriber<T> rather than the runtime type of the object provided to InterfacePublisher<T>::addSubscription().
void addSubscription(InterfaceSubscriber<T>* subsc)
{
mSignalArgs.connect(std::bind(&InterfaceSubscriber<T>::onData,
*subsc, ...);
// ^~~ sliced
}
To resolve this, either pass the pointer directly or pass a std::ref object as the instance.
void addSubscription(InterfaceSubscriber<T>* subsc)
{
mSignalArgs.connect(std::bind(&InterfaceSubscriber<T>::onData,
subsc, ...);
// ^~~ pointer
}
or
void addSubscription(InterfaceSubscriber<T>* subsc)
{
mSignalArgs.connect(std::bind(&InterfaceSubscriber<T>::onData,
std::ref(*subsc), ...);
// ^~~ reference
}
Working on a console application and I am trying to figure out a way that allows users to enter an object property along with a value. For example
class Box{
public:
int height;
int width;
int length;
};
int main(){
string memberName,value
cin>>memberName>>value;
}
If a user inputs height, then by using memberName and value how can I change height's value to whatever the user input. I want to make this work so that one can add another class and get the same functionality.
I am considering using maps, but not entirely sure how would I go on doing that.
Here's a complex way to do it, but it does exactly what you were trying to do in the first place (easily apply it to any structure):
#include <iostream>
#include <string>
#include <map>
/////////////////////////////////////////
// HELPERS
template<class T>
class MemberPtrBase
{
public:
virtual std::istream& Read(std::istream& is, T& object) = 0;
virtual ~MemberPtrBase() {}
};
template<class T, class V>
class MemberPtr : public MemberPtrBase<T>
{
V T::*member;
public:
MemberPtr(V T::*ptr)
: member(ptr)
{}
std::istream& Read(std::istream& is, T& object)
{
return is >> (object.*member);
}
};
template<class T>
class MemberMap
{
typedef std::map<std::string, MemberPtrBase<T>*> MapType;
MapType members;
public:
MemberMap() {}
~MemberMap()
{
for (MapType::iterator it = members.begin(); it != members.end(); ++it)
delete it->second;
}
template<class V>
void Register(std::string const& name, V T::*ptr)
{
members[name] = new MemberPtr<T, V>(ptr);
}
std::istream& ReadValue(std::istream& is, T& object)
{
std::string name;
is >> name;
if (members.find(name) == members.end())
{
std::cerr << "Unknown member: " << name << std::endl;
return is;
}
return members[name]->Read(is, object);
}
};
///////////////////////////////////////////
class Box
{
public:
int width;
int height;
int length;
static MemberMap<Box> members;
};
MemberMap<Box> Box::members;
class Circle
{
public:
int x;
int y;
int radius;
static MemberMap<Circle> members;
};
MemberMap<Circle> Circle::members;
int main()
{
Box::members.Register("width", &Box::width);
Box::members.Register("height", &Box::height);
Box::members.Register("length", &Box::length);
Circle::members.Register("x", &Circle::x);
Circle::members.Register("y", &Circle::y);
Circle::members.Register("radius", &Circle::radius);
Box box;
Box::members.ReadValue(std::cin, box);
return 0;
}
using a map is indeed the way to do it. will edit shortly with code example
#include "stdafx.h"
#include <iostream>
#include <map>
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
std::map<std::string,std::string> mapData;
std::string name,value;
std::cout << "Enter Name:\n";
std::cin >> name;
std::cout << "\n\nEnter Data\n";
std::cin >> value;
mapData[name] = value;
return 0;
}
or you can have a class wrapping a map if you need to do various other operations on the map or in between (such as validate the input or do other operations with the input before you store it in the map).
// example of class wrapping a map
class MapContainer {
private:
map<string,string> _map;
public:
void addValue(const string& name, const string& value) {
_map[name] = value;
}
string getValue(const string& name) {
return _map[name];
}
}
Simply, you can't do it in a general way; there's no way to access member variables basing on their name from runtime.
This is typically solved by creating an if-else chain (or switch) that allows you to convert data to information:
char type;
float height;
int age;
cin >> type;
switch(type) {
case 'h': cin >> height; break;
case 'a': cin >> age; break;
}
This is inflexible, but so is your class structure, right? If you want to make it dynamic, creating bindings as in #riv's answer makes little sense; any change in class will need proper clause again. It would be better to simply decide that some fields are dynamically stored on map:
class C {
int iAlwaysHaveThat;
map<variant<int,float,string>> dynamicValues;
};
That way you can parse configuration files such as:
Obj [
a = 5,
b = 3.14,
name = "some string value"
]
And then access them by (depending on actual needs) a function returning optional:
optional<variant<...>> getDynamicValue(string const& name) { ... }
Which could also fill in defaults basing on some other object, for example:
{
// ...
auto v = dynamicValues.find(name);
if (v == dynamicValues.end())
return defaultValuesProvider.getDefault(name);
// ...
}
That's a solution that could be actually useful for some uses, however I would probably embed a script language anyway.
I often want to define new 'Exception' classes, but need to have an appropriate constructor defined because constructors aren't inherited.
class MyException : public Exception
{
public:
MyException (const UString Msg) : Exception(Msg)
{
};
}
Typedefs don't work for this, because they are simply aliases, not new classes. Currently, to avoid repeating this trivial boilerplate, I use a #define which does the donkeywork.
#define TEXCEPTION(T) class T : public Exception \
{ \
public:\
T(const UString Msg) : Exception(Msg) {}; \
}
...
TEXCEPTION(MyException);
But I keep wondering if there's a better way of achieving this - maybe with templates, or some new C++0x feature
If you really want to have new classes derived from Exception, as opposed to having a template parameterized by a parameter, there is no way around writing your own constructor that just delegates the arguments without using a macro. C++0x will have the ability what you need by using something like
class MyException : public Exception
{
public:
using Exception::Exception;
};
You can read about the details of that (seem to have quite a bit of extra rules) in 12.9 "Inheriting Constructors" in the latest draft of C++0x.
In the meantime, i would recommend a policy based design (made small text, because the OP accepted the above, and not this policy stuff):
// deriving from Impl first is crucial, so it's built first
// before Exception and its Ctor can be used.
template<typename Impl>
struct ExceptionT : Impl, Exception {
// taking a tuple with the arguments.
ExceptionT(arg_types const& t = arg_types())
:Exception(Impl::Ctor(t)) { }
// taking a string. plain old stuff
ExceptionT(std::string const& s):Exception(Impl::Ctor(s)) { }
};
struct ExceptionDefImpl {
typedef boost::tuple<> arg_types;
// user defined ctor args can be done using a tuple
std::string Ctor(arg_types const& s) {
return std::string();
}
std::string const& Ctor(std::string const& s) {
return s;
}
};
// will inherit Ctor modifier from DefImpl.
struct MemoryLost : ExceptionDefImpl {
typedef boost::tuple<int> arg_types;
std::string Ctor(arg_types const& s) {
std::ostringstream os;
os << "Only " << get<0>(s) << " bytes left!";
return os.str();
}
int getLeftBytes() const { return leftBytes; }
private:
int leftBytes;
};
struct StackOverflow : ExceptionDefImpl { };
// alias for the common exceptions
typedef ExceptionT<MemoryLost> MemoryLostError;
typedef ExceptionT<StackOverflow> StackOverflowError;
void throws_mem() {
throw MemoryLostError(boost::make_tuple(5));
}
void throws_stack() { throw StackOverflowError(); }
int main() {
try { throws_mem(); }
catch(MemoryListError &m) { std::cout << "Left: " << m.getLeftBytes(); }
catch(StackOverflowError &m) { std::cout << "Stackoverflow happened"; }
}
You could parameterize your template class with an integer:
#include <iostream>
#include <string>
using namespace std;
enum ExceptionId {
EXCEPTION_FOO,
EXCEPTION_BAR
};
class Exception {
string msg_;
public:
Exception(const string& msg) : msg_(msg) { }
void print() { cout << msg_ << endl; }
};
template <int T>
class TException : public Exception {
public:
TException(const string& msg) : Exception(msg) {};
};
void
foo()
{
throw TException<EXCEPTION_FOO>("foo");
}
void
bar()
{
throw TException<EXCEPTION_BAR>("bar");
}
int
main(int argc, char *argv[])
{
try {
foo();
} catch (TException<EXCEPTION_FOO>& e) {
e.print();
};
try {
bar();
} catch (TException<EXCEPTION_BAR>& e) {
e.print();
};
return 0;
}
Although, I don't see why you would favor this over using a single class with an internal enumeration that is set/read at runtime:
class TException {
public:
enum Type { FOO, BAR };
TException(Type type, const string& msg) : Exception(msg), type_(type) {}
Type type() const { return type_; }
private:
Type type_;
};
Then just switch on the type when you catch a TException...
// You could put this in a different scope so it doesn't clutter your namespaces.
template<struct S> // Make S different for different exceptions.
class NewException :
public Exception
{
public:
NewException(const UString Msg) :
Exception(Msg)
{
}
};
// Create some new exceptions
struct MyExceptionStruct; typedef NewException<MyExceptionStruct> MyException;
struct YourExceptionStruct; typedef NewException<YourExceptionStruct> YourException;
struct OurExceptionStruct; typedef NewException<OurExceptionStruct> OurException;
// Or use a helper macro (which kinda defeats the purpose =])
#define MAKE_EXCEPTION(name) struct name##Struct; typedef NewException<name##Struct> name;
MAKE_EXCEPTION(MyException);
MAKE_EXCEPTION(YourException);
MAKE_EXCEPTION(OurException);
// Now use 'em
throw new MyException(":(");