различать статические и нестатические методы в С++ во время компиляции?

Для некоторой автоматизации трассировки для идентификации экземпляров я хочу вызвать:

  • нестатический метод содержащего объекта, возвращающий его идентификатор
  • что-то еще, что всегда возвращает один и тот же идентификатор

Мое текущее решение состоит в том, чтобы иметь базовый класс с методом which() и глобальной функцией which(), которую следует использовать, если не в контексте объекта. Однако это не работает для статических функций-членов, здесь компилятор предпочитает нестатический метод глобальному.

Упрощенный пример:

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
};

Могу ли я каким-то образом избежать использования обходных путей, таких как специальный макрос для статических функций-членов (возможно, с использованием некоторой магии шаблонов)?


person Georg Fritzsche    schedule 17.09.2009    source источник
comment
Я уверен, что есть способ сделать это, используя указатели на функции и используя некоторый связующий элемент для случая функции-члена. Но сначала я бы поставил вопрос о дизайне. Как вы думаете, почему вам нужно писать один и тот же код как в статических, так и в нестатических идентифицируемых функциях-членах? Как часто я могу решить эту проблему? может быть лучше, чем я застрял на этом пути решения моей проблемы, как мне продвинуться дальше?   -  person sbi    schedule 17.09.2009
comment
я хочу использовать тот же код, потому что хочу просто использовать один центральный макрос вместо одного для статического и одного для нестатического контекстов. может дизайн не тот, но по крайней мере я сам не вижу лучшего.   -  person Georg Fritzsche    schedule 17.09.2009


Ответы (3)


Вы можете использовать is_member_function_pointer из библиотеки Boost TypeTraits. Предложение sbi об использовании разного кода в статическом и нестатическом случаях, вероятно, лучше.

person Dan Hook    schedule 17.09.2009

Определите шаблон функции, который возвращает идентификатор по умолчанию для всех типов.

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

Специализируйте шаблон функции для определенного класса.

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(); }

Вызовите шаблон функции, передав экземпляр, который вы хотите идентифицировать.

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

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

    return 0;
}
person Chin Huang    schedule 17.09.2009
comment
Извините, но я не вижу, где это позволило бы мне вызывать which() в одном центральном макросе без другого кода для статических/нестатических контекстов. - person Georg Fritzsche; 17.09.2009
comment
Извините, я не заметил вашего требования к макросу без аргументов для идентификации экземпляра. Мое решение требует, чтобы вы передали экземпляр в качестве аргумента. - person Chin Huang; 18.09.2009

Вам нужен другой идентификатор для каждого экземпляра каждого класса, как в вашем примере, или вы просто пытаетесь определить, какой класс находится в трассировке?

Изменение вашей функции which() и члена _id на статические сделает их доступными для ваших статических функций-членов и, в качестве бонуса, уменьшит использование вашей памяти.

person Alan    schedule 17.09.2009
comment
да, я делаю это, чтобы идентифицировать разные экземпляры одного и того же класса и их дочерние элементы. - person Georg Fritzsche; 17.09.2009
comment
И в таком случае, для чего нужен статический метод и почему он должен иметь одно и то же тело? В противном случае вы могли бы: а) передать макрос ident (или функцию), что печатать (this-›what() или ::what()), или вы могли бы реализовать статику, например: { using :: which; идентификатор(); } - person UncleBens; 17.09.2009
comment
моя цель состоит в том, чтобы использовать один набор в основном автоматических макросов трассировки/журнала, а не какие-либо конкретные, в зависимости от контекста. они также должны, насколько это возможно, автоматически регистрировать, к какому основному экземпляру они принадлежат. {используя ::который(); ...} будет противоречить цели простоты и автоматизации, поскольку будет передавать явные сообщения. назовите меня ленивым, но я не хочу думать о том, в каком контексте я нахожусь, если я могу как-то автоматизировать это. - person Georg Fritzsche; 18.09.2009
comment
То есть вы говорите, что не хотите менять код вызова и не хотите менять макрос? Вы просто хотите, чтобы ваша идея работала? - person UncleBens; 18.09.2009
comment
Нет, я говорю, что не хочу вводить дополнительный макрос. И я не хочу ничего использовать вокруг макроса, чтобы заставить его работать в определенных контекстах. Мне просто нужен общий макрос, который работает во всех контекстах. - person Georg Fritzsche; 18.09.2009
comment
Ну, я не могу придумать способ сказать внутри макроса, в какой функции вы находитесь. - person UncleBens; 18.09.2009