Перегрузка функции шаблона c ++ для типа указателя - PullRequest
0 голосов
/ 14 января 2019

Я использую std::type_index объекты в качестве уникальных идентификаторов для классов состояний (в основном, ключи в фабричной функции для создания новых объектов ссылочного типа). Идентификатор класса, объекта этого класса и указатель на объект этого класса должны быть одинаковыми. Следовательно, я пытался сделать:

using stateid_t = std::type_index;
template<class T> inline stateid_t GetStateID() { return typeid(T); }
template<class T> inline stateid_t GetStateID(const T&) { return typeid(T); }
template<class T> inline stateid_t GetStateID(const T*) { return typeid(T); }

Однако третья версия никогда не вызывается с чем-то вроде GetStateID(this);, всегда вторая версия, с типом T, выведенным как «указатель на T».

Я думаю Я должен быть в состоянии сделать это как-то, используя std::enable_if, но я не могу придумать ничего, что работает.

Редактировать

Главное, что я хочу - это набор функций, удовлетворяющих

struct A{};
A a;
const A b;
//fixed asserts based on comments
assert(GetStateID<A>() == GetStateID(a));
assert(GetStateID(a) == GetStateID(&a));
assert(GetStateID(a) == GetStateID(b));

//added some new constraints
struct X : public A{};
X x;
assert(GetStateID<A>() != GetStateID<X>());
assert(GetStateID(a) != GetStateID(x));

Бонусные баллы за объяснение того, почему перегрузка указателя не выбирается.

1 Ответ

0 голосов
/ 14 января 2019

Предположительно, вы вызываете эти функции не из const функций-членов. Если это так, то stateid_t GetStateID(const T*) требует неявного преобразования (из U* в const U*, где U - это тип класса), тогда как stateid_t GetStateID(const T&) - нет (U будет U*). В контексте функции-члена const указатель this уже будет const U *, который не требует неявного преобразования и должен вызвать stateid_t GetStateID(const T*).

Удаление этих const должно решить проблему. И U*, и const U* предпочли бы stateid_t GetStateID(T*) вместо stateid_t GetStateID(T&).

Однако, возможно, вы пытаетесь реализовать решение решенной проблемы. Выражение typeid(std::remove_pointer_t<T>); должно производить то, что вы уже хотите. С точки зрения вашего кода, следующее должно работать для вас:

using stateid_t = std::type_index;
template<class T> inline stateid_t GetStateID() { 
    return typeid(std::remove_pointer_t<T>);
}

Редактировать: чтобы выполнить ваши требования к интерфейсу, вы можете добавить шаблон функции, который выводит T:

template<class T> inline stateid_t GetStateID(T&&) {
    return GetStateID<T>(); 
}
...