Reputation: 39
I'm looking for an easy-to-use macro for calling a function only once for a specific value. For example:
void foo( Object* obj )
{
// Print out the name of each object only once
DO_ONCE( obj, printf("This gets printed only once per object! %s\n",obj->GetName()) );
}
Then
Object obj1("obj1Name"),obj2("obj2Name");
foo(&obj1);
foo(&obj1);
foo(&obj2);
Should print out
This gets printed only once per object! obj1Name
This gets printed only once per object! obj2Name
Upvotes: 2
Views: 1797
Reputation: 829
Concept:
template<class t1> void do_once(t1* obj) {
static std::map<t1*,bool> was_here;
if (was_here[obj]==false) was_here[obj]=true, throw obj;
}
void ff(int * x)
{
try {do_once(x); } catch (int* obj) { printf("First time: %d\n",*obj);}
}
Upvotes: 0
Reputation: 25512
#include <set>
...
#define DO_ONCE(type, val, stmt) \
do \
{ \
type __tmp = (val); \
static std::set < type > __memo; \
if (__memo.find(__tmp) == __memo.end()) \
{ \
__memo.insert(__tmp); \
do { stmt; } while(0); \
} \
} \
while(0)
...
DO_ONCE(Object *, obj, printf(...));
Upvotes: 1
Reputation: 545508
Put your objects in a container and filter/group so each one only appears once. This can be done trivially by using set
(or std::tr1::unordered_set
) as the container for your objects. This effectively makes them unique. You can then iterate over the container.
Or, as others have proposed, use the container inside the function as a memoization device. However, in general I think explicitly grouping the results may be more appropriate.
Upvotes: 3
Reputation: 156138
You'll probably need to memoize the objects. Something linke
bool do_once( Object * obj )
{
static std::set<Object*> memo;
if ( memo.count(obj) )
{
memo.insert(obj);
return true;
}
return false;
}
#define DO_ONCE(o,a) (do_once(obj) && a)
Upvotes: 1
Reputation: 59804
#include <iostream>
#include <ostream>
#include <set>
#include <string>
class Object
{
public:
Object( const std::string& name ):
name_( name )
{}
std::string GetName() const
{
return name_;
}
private:
std::string name_;
};
void print( Object* object )
{
std::cout << object->GetName() << std::endl;
}
template <typename T, typename TFunction>
void doOnce( T* object, TFunction function )
{
static std::set<T*> objectsThatWasThere;
if ( objectsThatWasThere.end() == objectsThatWasThere.find( object ) )
{
function( object );
objectsThatWasThere.insert( object );
}
}
int main()
{
Object obj1("Test");
Object obj2("The");
doOnce( &obj1, print );
doOnce( &obj1, print );
doOnce( &obj1, print );
doOnce( &obj2, print );
doOnce( &obj2, print );
doOnce( &obj2, print );
return 0;
}
Upvotes: 1
Reputation: 506847
I prefer a map
void foo( Object* obj ){
// Print out the name of each object only once
static std::map<Object*, size_t> calls;
if(calls[obj] == 0) {
std::cout << "This gets printed only once per object! "
<< obj->GetName();
calls[obj] = 1;
}
}
You may also decide to increment the counter if you want to count the calls too. But note that it is also not really fail-safe. If you delete an object, and then new it again and it happens to get the same address, it will be assumed to be already printed.
Upvotes: 2