указатели — Почему шаблон & lt; typename T & gt; оценивать Foo вместо Bar в Stack Overflow

В этом коде почему typename T (в функции Test (…)) вычисляет тип Foo вместо типа Bar? И как я могу изменить это так, чтобы это стало типом Бар?

#include <typeinfo>
using namespace std;

struct Foo
{
virtual ~Foo() { }
};

struct Bar : public Foo
{
};

template<typename T>
bool Test(T foo)
{
return (typeid(foo) == typeid(Bar));
}

int main()
{
Bar bar;
Foo *foo = &bar;
bool THIS_IS_TRUE = (typeid(*foo) == typeid(Bar));
bool WHY_ISNT_THIS = Test(*foo);
return 0;
}

2

Решение

Шаблоны выводятся на основе статического типа, а не типа динамического элемента. Код статически связан и создается в соответствии с тем, что знает компилятор во время компиляции, независимо от того, какие типы существуют во время выполнения. Кроме того, когда вы проходите *foo по значению вы все равно нарезаете объект.

6

Другие решения

Шаблоны создаются во время компиляции, и поэтому они не могут определить тип среды выполнения, которую вы им передаете.

В любом случае, поскольку вы передаете по значению, вы собираетесь преобразовывать и разрезать объект, что приведет к потере информации об исходном типе. Bar, Попробуйте ссылку вместо этого:

template<typename T>
bool Test(T& foo)
{
return (typeid(foo) == typeid(Bar));
}

T все равно будет выведено Foo, но typeid(foo) должно быть Bar,

4

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

Попробуй это :

template<typename T>
bool Test(T foo)
{
return (typeid(*foo) == typeid(Bar));
}

int main()
{
Bar bar;
Foo *foo = &bar;
bool THIS_IS_TRUE = (typeid(*foo) == typeid(Bar));
bool WHY_ISNT_THIS = Test(foo);
return 0;
}
1

То, что вы хотите сделать, не работает. Вот альтернативный подход, где я в основном строю свою собственную инфраструктуру типов:

#include <functional>
struct Base {
protected:
virtual ~Base() {}
Base() {}
public:
virtual size_t SizeRequired() const = 0;
virtual std::function<Base*(unsigned char* buffer)> Constructor() const = 0;
// note that standard delete is not standards compliant, because the memory
// was allocated as an array of unsigned char's
void SelfDelete() {
SelfDestroy();
delete[] reinterpret_cast<unsigned char*>(this);
}

// you can also create these things in other storage locations:
void SelfDestroy() {
this->~Base();
}
static void Delete( Base* b ) {
if (b)
b->SelfDelete();
}
std::function<Base*()> AllocateAndConstructor() const {
size_t required = this->SizeRequired();
auto constructor = this->Constructor();
return [required, constructor]()->Base* {
unsigned char* buff = new unsigned char[ required ];
return constructor( buff );
};
}
};

// CRTP class (google CRTP if you are confused what I'm doing)
template<typename Child>
struct BaseHelper: Base {
static Base* Construct(unsigned char* buffer) {
return new(buffer) Child();
}
static Base* Create() {
unsigned char* buff = new unsigned char[ sizeof(Child) ];
return Construct( buff );
};
virtual size_t SizeRequired() const {
return sizeof(Child);
}
virtual std::function<Base*(unsigned char* buffer)> Constructor() const {
return &BaseHelper<Child>::Construct;
}
};

// use:

struct Bar: BaseHelper<Bar> {
};
struct Foo: BaseHelper<Foo> {
};

Base* test(Base* b) {
auto creator = b->AllocateAndConstructor();
return creator();
}
#include <iostream>
int main() {
Base* b = Bar::Create(); // creates a Bar
Base* b2 = test(b); // creates another Bar, because b is a Bar
Base* f = Foo::Create(); // creates a Foo
Base* f2 = test(f); // creates another Foo, because f is a Foo
std::cout << (typeid(*b) == typeid(*b2)) << " == 1\n";
std::cout << (typeid(*f) == typeid(*f2)) << " == 1\n";
std::cout << (typeid(*f) == typeid(*b)) << " == 0\n";
Base::Delete(b);
Base::Delete(b2);
Base::Delete(f);
Base::Delete(f2);
Base::Delete(0); // does not crash
};

это означает, что каждый экземпляр времени выполнения базы несет с собой доступ к возможности создания экземпляров базы. Переопределение new и delete может работать лучше, чем использование описанных выше операций создания и удаления замены, и позволит кому-то создавать эти вещи в стеке.

Я бы посоветовал против такого рода техники, если вы не знаете, что делаете.

Однако существуют относительно распространенные модели, такие как клонирование и фабрики, которые близки к вышесказанному, но немного менее глупы.

0
По вопросам рекламы [email protected]