使用VS2012的enable_if和构造函数

enable_if and constructor with VS2012

本文关键字:if 构造函数 enable VS2012 使用      更新时间:2023-10-16

我正在尝试有条件地启用构造函数模板。对于完全兼容c++ 11的编译器,我知道如何使用额外的默认模板参数来实现这一点。然而,我需要支持VS2012,它有std::enable_if,但不支持默认的函数模板参数。

在c++ 11中,我会这样写:
template<typename T>
struct Class
{
  template<typename O, 
           typename = typename std::enable_if<std::is_convertible<O*, T*>::value>::type>
  Class(O*) {}
};

我尝试了以下,但它给出了一个错误C4336和各种后续错误:

template<typename T>
struct Class
{
  template <typename O>
  Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type *= nullptr)
  {
  }
};

是否有办法使这个工作与VS2012?

添加

:

类的用法如下:

struct X { };
struct X2 : X { };
struct Y { };
struct Client
{
  Client(Class<X> x) {}
  Client(Class<Y> y) {}
};
void test() {
  X2* x2;
  Client client(x2); // error C2668: ambiguous call to overloaded function
                     // (without std::enable_if)
}

你是所以接近解决方案!

template<typename T>
struct Class
{
    template <typename O>
    Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type * = nullptr)
    {
    }
};

你发现区别了吗?形参表中的*=被解析为乘法/赋值操作符,而不是后跟默认实参的指针类型。因此,语法错误。

这是因为c++解析器被指定为在形成标记时消耗尽可能多的字符(所谓的Maximum Munch Rule)。按预期添加一个空格将它分成两个单独的标记。

恐怕,您必须使用helper构造函数(我没有找到绕过它的方法)。但是像这样的代码应该可以工作:

#include <type_traits>
template<typename T>
struct Class
{
  template<typename O>
  Class(O* o) { construct(o, std::integral_constant<bool, std::is_convertible<T*, O*>::value>()); }
  template<class O>
  void construct(O*, std::true_type ) { /* convertible */ }
  template<class O>
  void construct(O*, ... ) { /* not convertible */ }
};
struct X { };
struct Y : public X { };
void check() {
  X x;
  int i;
  Class<Y> cl(&x);
  Class<Y> cl1(&i);
}

从c++ 11开始,您还可以使用委托构造函数来完成此操作:

template<typename T>
class Class {
    template<typename O>
    Class(O *o, std::true_type) {}
    template<typename O>
    Class(O *o, std::false_type) {}
public:
    template<typename O>
    Class(O *o): Class(o, typename std::is_convertible<O*, T*>::type) {}
};

基本思想是标签调度之一,也许它在VS2012中也工作得很好。