I have the following function template:
template <typename TypeName>
TypeName AssignDefaultIfNull(VARIANT Variant, TypeName & Value) {
if ((Variant.vt != VT_NULL) || (Variant.vt != VT_EMPTY))
{
CComVariant CV = Variant;
if (CV.vt != TypeName) {} // << HERE I WANT TO COMPARE THOSE TWO, BUT THEY'RE DIFFERENT THINGS. >>
}
else
{
// Default Value
}
return Value;
}
Sometimes, I use above function template like:
LONG LongValue = AssignDefaultIfNull<LONG>(rcNormalPositionBottom, lpwndpl.rcNormalPosition.bottom);
I want above to compare VARIANT
's VARTYPE (vt)
with the given typename TypeName
and if matches, then perform some operations with them.
I tried with !=
operator, but it cannot compare because VARTYPE
is unsigned short
and TypeName
is a typename
.
I also tried like this:
if (CV.vt != (VARTYPE)typeid(TypeName).name()) {}
But compiler gives a warning:
C4302: 'type cast': truncation from 'const char*' to 'VARTYPE'
Isn't there any possible way to compare those two types correctly?
Thanks in advance.
To implement a similar concept using std::variant
you can define a visitor which returns a specified default value if the requested type is not stored in the variant. Using an instantiator function one can get around explicitly specifying template argument and let template argument deduction do the heavy lifting.
Needs C++17.
#include <iostream>
#include <utility>
#include <variant>
// Leave blank incomplete to prevent uninitialized variant from
// compiling.
// struct blank;
struct blank {};
using Variant = std::variant<blank,
unsigned int,
int,
unsigned long,
long
/* ... */
>;
template < typename R >
class DefaultVisitor
{
R m_r;
public:
DefaultVisitor(R const& r) : m_r(r) {}
R operator() (R const& r) { return r; }
template < typename T >
R operator() (T const&) { return m_r; }
};
template < typename R >
DefaultVisitor<R> make_default_visitor(R const& r)
{
return DefaultVisitor<R>(r);
}
int main()
{
Variant v(long{0});
Variant w;
std::cout << std::visit(make_default_visitor(long{12}), v) << '\n'; // 0
std::cout << std::visit(make_default_visitor(int{17}), v) << '\n'; // 17
}
Alternatively you could use Boost.Variant which is available before C++17. This should compile from C++11 onward.
#include <iostream>
#include <utility>
#include <boost/variant.hpp>
using Variant = boost::variant<boost::blank,
unsigned int,
int,
unsigned long,
long
/* ... */
>;
template < typename R >
class DefaultVisitor : boost::static_visitor<R>
{
R m_r;
public:
using result_type = R ; // need this to compile in C++11
DefaultVisitor(R const& r) : m_r(r) {}
R operator() (R const& r) const { return r; }
template < typename T >
R operator() (T const&) const { return m_r; }
};
template < typename R >
DefaultVisitor<R> make_default_visitor(R const& r)
{
return DefaultVisitor<R>(r);
}
int main()
{
Variant v(long{0});
Variant w;
std::cout << boost::apply_visitor(make_default_visitor(long{12}), v) << '\n'; // 0
std::cout << boost::apply_visitor(make_default_visitor(int{17}), v) << '\n'; // 17
}