Как рекурсивно разыменовать указатель (C ++ 03)? - PullRequest
13 голосов
/ 05 ноября 2011

Я пытаюсь рекурсивно разыменовать указатель в C ++.

Если передан объект, который является , а не указателем (включая интеллектуальные указатели), я просто хочу вернуть сам объект, по ссылке, если это возможно.

У меня есть этот код:

template<typename T> static T &dereference(T &v) { return v; }
template<typename T> static const T &dereference(const T &v) { return v; }
template<typename T> static T &dereference(T *v) { return dereference(*v); }

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

Итак, как я могу "остановить" процесс разыменования, если тип разыменования имеет тот же тип, что и исходный объект?

Примечание:

Я вижу, что мой вопрос был помечен как дубликат аналогичного вопроса, использующего Boost; однако мне нужно решение без Boost (или любых других библиотек).


* * 1 022 Пример: * 1 023 *
template<typename T> T &dereference(T &v) { return v; }
template<typename T> const T &dereference(const T &v) { return v; }
template<typename T> T &dereference(T *v) { return dereference(*v); }

template<typename TCallback /* void(int) */>
void invoke(TCallback callback) { dereference(callback)(); }

void callback() { }

struct Callback {
     static void callback() { }
     void operator()() { }
};

int main() {
    Callback obj;
    invoke(Callback());          // Should work (and does)
    invoke(obj);                 // Should also work (and does)
    invoke(&obj);                // Should also work (and does)
    invoke(Callback::callback);  // Should also work (but doesn't)
    invoke(&Callback::callback); // Should also work (but doesn't)
    invoke(callback);            // Should also work (but doesn't)
    invoke(&callback);           // Should also work (but doesn't)
    return 0;
}

1 Ответ

6 голосов
/ 06 ноября 2011

Никаких зависимостей, просто, должно работать на MSVC-2008.

template<typename T>
struct is_function
{
    static char     check(...);
    static double   check(const volatile void*); // function pointers are not convertible to void*
    static T        from;
    enum { value = sizeof(check(from)) != sizeof(char) };
};

template<bool, typename T = void>
struct enable_if{};

template<typename T>
struct enable_if<true, T>{typedef T type;};

template<typename T> 
T& dereference(T &v){return v;}

template<typename T> 
const T& dereference(const T& v){return v;}

template<typename T> 
typename enable_if<!is_function<T>::value, T&>::type dereference(T* v){return dereference(*v);}
...