I am currently implementing a class that is a three-way map, meaning each "index" has three keys and one can retrieve each. The function get is defined as:
template<typename returnType, typename getType>
returnType get(getType getVal) {
if (typeid(returnType) == typeid(getType)) {
return getVal;
}
// Here the appropriate value is gotten. Not important for this.
// This is returned just in-case nothing is found.
return *new returnType;
}
This doesn't compile, because getType is not always equal to returnType, which is guaranteed by my check. Is there a way to make this compile, because the getting process is quite expensive. I've tried to just do return returnType(getVal);
, which only works if returnType
has a constructor for getType
.
Solutions I could imagine but didn't manage to pull of:
- template specialization
- disable type-checking (similar to rust's
unsafe
)
P.S: I know this optimisation doesn't make a lot of sense, still would like to know if it's possible to compile.
CodePudding user response:
typeid
is not meant to be used this way at compile-time. If you want to operate on types at compile-time, use the tools from #include<type_traits>
. typeid
is meant to be used if you need to operate on types at runtime (e.g. store ids for types in a container or obtain a printable name for a type) or you need to determine the actual type of a polymorphic pointer/lvalue at runtime.
To compare types at compile-time use std::is_same_v<returnType, getType>
. Since C 17 it is also possible to conditionally compile branches of an if
in a template, using if constexpr
instead of if
:
template<typename returnType, typename getType>
returnType get(getType getVal) {
if constexpr (std::is_same_v<returnType, getType>) {
return getVal;
} else {
// Here the appropriate value is gotten. Not important for this.
// This is returned just in-case nothing is found.
return /*some returnType*/;
}
}
Also note that applying *
to a new
expression is practically always wrong. You are returning *new returnType
immediately by-value. That is a guaranteed immediate memory leak. new
returns a pointer to newly allocated memory with a new object of the given type in it. Returning the dereferenced pointer by-value means that this new object is again copied into the return value and at the same time the lvalue/pointer to the first newly created object is lost in the copy/move constructor.
To create an object to return directly, do not use new
. Just return a temporary object using the functional explicit cast notation:
return returnType{};
or even shorter, since returnType
is already mentioned in the function return type:
return {};
new
is very rarely needed directly in C . If a variable or a temporary as above also works, then don't use new
, and if that doesn't work reconsider whether you shouldn't be using std::unique_ptr
/std::shared_ptr
/std::vector
/std::string
/etc. instead of new
.