【问题标题】:Compare VARTYPE and typeid().name / typename in function templates比较函数模板中的 VARTYPE 和 typeid().name / typename
【发布时间】:2017-07-19 01:01:54
【问题描述】:

我有以下函数模板:

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;
}

有时,我使用上面的函数模板,例如:

LONG LongValue = AssignDefaultIfNull<LONG>(rcNormalPositionBottom, lpwndpl.rcNormalPosition.bottom);

我想在上面将VARIANTVARTYPE (vt) 与给定的类型名TypeName 进行比较,如果匹配,则对它们执行一些操作。

我尝试使用!= 运算符,但它无法比较,因为VARTYPEunsigned shortTypeNametypename

我也试过这样:

if (CV.vt != (VARTYPE)typeid(TypeName).name()) {}

但是编译器给出警告:

C4302:“类型转换”:从“const char*”截断为“VARTYPE”

有没有办法正确比较这两种类型?

提前致谢。

【问题讨论】:

  • 不清楚您的代码中Variant 指的是什么类型。如果您使用的是std::variant,您可以使用if (std::holds_alternative&lt;TypeName&gt;(CV)) { ... }
  • 好的,但是它是什么type?哪个标头定义了VARIANTCComVariant
  • 我没有 Visual C++,但你可以试试if (CV.vt != CComVariant(TypeName{}).vt) { ... }(需要 C++11 来实现统一的初始化语法)。这会创建一个临时的 CComVariant,它包装默认初始化值 TypeName 并检索 .vt 成员。
  • 在 C++11 之前这可能有效:if (CV.vt != CComVariant((TypeName())).vt) { ... }

标签: c++ templates typename


【解决方案1】:

要使用std::variant 实现类似的概念,您可以定义一个访问者,如果请求的类型未存储在变体中,则该访问者返回指定的默认值。使用实例化函数可以绕过显式指定模板参数,让模板参数推导完成繁重的工作。

需要 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
}

或者,您可以使用 C++17 之前可用的 Boost.Variant。这应该从 C++11 开始编译。

#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
}

【讨论】:

  • 谢谢!我还没有尝试过,如果出现问题,我会尝试提出一个新问题。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 2015-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-15
相关资源
最近更新 更多