views:

242

answers:

3

For some tracing automation for identifying instances i want to call either:

  • a non-static method of the containing object returning its identifier
  • something else which always returns the same id

My current solution is to have a base class with a method which() and a global function which() which should be used if not in the context of an object. This however does not work for static member functions, here the compiler prefers the non-static method over the global one.

Simplified example:

class IdentBase
{
public:
  Ident(const std::string& id) _id(id) {}
  const std::string& which() const { return _id; }
private:
  const std::string _id;
};

const std::string& which() { static const std::string s("bar"); return s; }

#define ident() std::cout << which() << std::endl

class Identifiable : public IdentBase
{
public:
  Identifiable() : Ident("foo") {}
  void works() { ident(); }
  static void doesnt_work() { ident(); } // problem here
};

Can i somehow avoid using work-arounds like a special macro for static member functions (maybe using some template magic)?

A: 

Do you need a different identifier for every instance of each class as in your example, or are you just trying to identify which class is in the trace?

Changing your which() function and _id member to static would expose them both to your static member functions, and as a bonus decrease your memory usage.

Alan
yes, i do that in order to identify different instances of the same class and their childs.
Georg Fritzsche
And in that case, what is the static method for and why does it have to have the same body? Otherwise you could a) pass the ident macro (or function) what to print (this->which() or ::which()), or you could implement the static like: { using ::which; ident(); }
UncleBens
Georg Fritzsche
So you are saying that you don't want to change the calling code and you don't want to change the macro? You just want your idea to "work"?
UncleBens
Nope, i'm saying i don't want to introduce an additional macro. And i don't wan't to use anything around the macro to make it work in certain contexts. I simply want a generic macro that works in all contexts.
Georg Fritzsche
Well I can't think of a way to tell inside the macro, what kind of function you are in.
UncleBens
A: 

You might be able to to use is_member_function_pointer from the Boost TypeTraits library. sbi's suggestion of using different code in the static and non-static cases is probably better though.

Dan Hook
quick test looks good, thanks.
Georg Fritzsche
+1  A: 

Define a function template that returns a default identifier for all types.

template<typename T>
const std::string& which(const T& object)
{ static const std::string s("bar"); return s; }

Specialize the function template for the specific class.

class IdentBase
{
public:
    IdentBase(const std::string& id): _id(id) {}
    const std::string& id() const { return _id; }
private:
    const std::string _id;
};

template<>
const std::string& which(const IdentBase& object)
{ return object.id(); }

Call the function template by passing an instance that you want to identify.

int main()
{
    int i;
    std::cout << which(i) << std::endl;

    IdentBase foo("foo");
    std::cout << which(foo) << std::endl;

    return 0;
}
Jim Huang
Sorry, but i don't see where that would allow me to invoke which() in one central macro without different code for static/non-static contexts.
Georg Fritzsche
Sorry, I didn't notice your requirement for a no-argument macro to identify the instance. My solution requires you to pass the instance as the argument.
Jim Huang