Answer of your question
if statements are not marked constexpr
The reason why your code does not compile is because, even if the if statements will be evaluated to false at compile time, the branches contained by those if statements will be compiled.
In your example, you can mark those if statements as constexpr to compile the code.
However, it will (probably) not work as you intend it to, because the type of property will be an rvalue of the pointer you passed to the constructor.
Here is an example of how I made it work (if I understood correctly what you were trying to do:
struct PropertyPointer {
    int type;
    std::string name;
    union {
        std::reference_wrapper<int*> int_reference;
        std::reference_wrapper<double*> double_reference;
        std::reference_wrapper<float*> float_reference;
        std::reference_wrapper<std::string*> string_reference;
    };
    PropertyPointer(std::string name, auto&& property): name{name} {
        using Type = ::std::remove_cvref_t<decltype(property)>;
        if constexpr (std::is_same<Type, int*>::value) {
            type = 'i';
            int_reference = property;
        } else if constexpr (std::is_same<Type, double*>::value) {
            type = 'd';
            double_reference = property;
        } else if constexpr (std::is_same<Type, float*>::value) {
            type = 'f';
            float_reference = property;
        } else if constexpr (std::is_same<Type, std::string*>::value) {
            type = 's';
            string_reference = property;
        }
    }
};
std::variant
It seems to me that you are not familiar with std::variant.
The class template std::variant represents a type-safe union.
source
Its job is to replace unions (that is a C feature) with type safe classes with extra functionalities.
Here is a quick example of how I would have done it:
class PropertyPointer {
public:
    PropertyPointer(
        auto&& property
    )
        : m_value{ &property }
    {
        // compare types if you want it to compile but have the object empty
    }
    template <
        typename T
    > [[ nodiscard ]] bool hasType() // true if the types matches the one inside (pointer or not)
    {
        using Type = ::std::remove_cvref_t<::std::remove_pointer_t<::std::remove_cvref_t<T>>>;
        return std::holds_alternative<Type*>(m_value);
    }
private:
    ::std::variant<int*, float*, double*, ::std::string*> m_value;
};
int main()
{
    PropertyPointer property{ ::std::string{ "yes" } };
    property.hasType<int>(); // false
    property.hasType<float>(); // false
    property.hasType<double>(); // false
    property.hasType<::std::string>(); // true
    property.hasType<const ::std::string>(); // true
    property.hasType<::std::string&>(); // true
    property.hasType<const ::std::string*>(); // true
    property.hasType<const ::std::string *const>(); // true
}
This example is here to show you that you can add some extra features like comparing with and without the pointer for the same behavior.
This example isn't here to tell you that "it is how it has to be done" but rather an example of how modern c++ features can make your life easier.