std::is_same does not appear to be working properly.

Asked 2 years ago, Updated 2 years ago, 151 views

Hello, everyone I have a question because there was a slight error in writing the c++ and stl codes. The code with the error first is as follows. An error occurs in the annotated area is processed.

template<typename T>
void D::Store() {
    // // remove all type cvr.
    using originalType = std::decay_t<std::remove_pointer_t<T> >;
    originalType* component = new originalType();

    If(std::is_same<originalType, A>:value) { // Error!!
        this->mA = component;
    } else if(std::is_same<originalType, B>::value) { // Error!!
        this->mB = component;
    } else if(std::is_same<originalType, C>:value) { // Error!!
        this->mC = component;
    }
    mComponents.push_back(component);
}

Types A, B, and C are predefined, and pointers corresponding to those types are defined as members in the class.

class D {
    D();
    ~D();

    template<typename T>
    void Store();

private:
    A* mA;
    B* mB;
    C* mC;
    std::vector<Parent*> mComponents;
}

If the type T handed over to the store is one of the types A, B, and C, it is stored in the pointer of the corresponding member and cached in the vector data type. Of course, Type A, B, C all inherit Parent. Besides that, class type E, F... And so on, there are several classes that inherit Parent.

By the way, the error comes out in the part where std::is_same. The error message displays an error such as Assigning to 'A*' from incompatible type 'originalType*' (aka 'E*").

What I want is to save it in the member variable only when A, B, and C types are given, so how can I make it work properly?

For reference, the development environment is xcode 7.3.1 version, and os is os xel capitan.

c++ stl c++11

2022-09-22 21:51

2 Answers

When a template is specialized, the compiler attempts to compile a specialized version. For example, consider specializing in Store<A>.

template<>
void D::Store<A>() {
    A* component = new A(); // It's not exactly this, but... It's not important.

    if(std::is_same<A, A>::value) {
        this->mA = component;
    } } else if(std::is_same<A, B>::value) {
        this->mB = component; // Error
    } } else if(std::is_same<A, C>::value) {
        this->mC = component; // Error
    }
    mComponents.push_back(component);
}

Even if the conditional part of the if statement is false, the code must be a legitimate C++ code. An error occurs due to a type mismatch between this->mB (or mC) and component. Cygwin GCC 5.4.0 shows this error message.

test.cpp: In instantiation of ‘void D::Store() [with T = A]’:
test.cpp:53:15:   required from here
test.cpp:35:18: error: cannot convert ‘originalType* {aka A*}’ to ‘B*’ in assignment
         this->mB = component;

Because of this problem, you simply don't use if when you're meta-programming templates. Instead, there are some things that act as if, in this case, a technique called tag dispatch seems appropriate.

struct tag_none { };
struct tag_A { };
struct tag_B { };
struct tag_C { };

template <typename T>
struct component_tag { using type = tag_none; };
template <>
struct component_tag <A> { using type = tag_A; };
template <>
struct component_tag <B> { using type = tag_B; };
template <>
struct component_tag <C> { using type = tag_C; };

class D
{
public:
    template <typename T>
    void Store();

private:
    void Store_impl(void*, tag_none);
    void Store_impl(A* component, tag_A);
    void Store_impl(B* component, tag_B);
    void Store_impl(C* component, tag_C);

    A *mA;
    B *mB;
    C *mC;
    std::vector<Parent*> mComponents;
};

template <typename T>
void D::Store()
{
    using originalType = std::decay_t<std::remove_pointer_t<T> >;
    originalType* component = new originalType();

    Store_impl(component, typename component_tag<originalType>::type { });

    mComponents.push_back(component);
}

void D::Store_impl(void*, tag_none)
{
    // // do nothing
}

void D::Store_impl(A* component, tag_A)
{
    mA = component;
}

void D::Store_impl(B* component, tag_B)
{
    mB = component;
}

void D::Store_impl(C* component, tag_C)
{
    mC = component;
}

As you can see in the code, we're overloading the function with an extra argument called tag. This is an example of how it's actually compiled.


2022-09-22 21:51

It's more like a trick. Why don't you use dynamic_cast?

void D::Store(Parent *t) {
    if(dynamic_cast<A*>(t)) {
        this->mA = (A*)t;
    } } else if (dynamic_cast<B*>(t)) { 
        this->mB = (B*)t;
    } } else if (dynamic_cast<C*>(t)) {
        this->mC = (C*)t;
    }
    mComponents.push_back(t);
}

dynamic_cast is possible only when the extinction of Parent is declared virtual.


2022-09-22 21:51

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.