enable_if 和 VS2012 的构造函数
enable_if and constructor with VS2012
我正在尝试有条件地启用构造函数模板。使用完全兼容 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 一起工作吗?
加法:
class 的用法如下:
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)
}
恐怕,您必须使用辅助构造函数(我没有找到绕过它的方法)。但是这样的事情应该有效:
#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。
有关详细信息,请参阅 here。
您所以接近解决方案!
template<typename T>
struct Class
{
template <typename O>
Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type * = nullptr)
{
}
};
你看出区别了吗?参数列表中的 *=
被解析为 multiplication/assignment operator,而不是后跟默认参数的指针类型。因此,语法错误。
这是因为C++解析器被指定在形成token时消耗尽可能多的字符(所谓的最大蒙克规则)。添加 space 会按预期将其拆分为两个单独的标记。
我正在尝试有条件地启用构造函数模板。使用完全兼容 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 一起工作吗?
加法:
class 的用法如下:
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)
}
恐怕,您必须使用辅助构造函数(我没有找到绕过它的方法)。但是这样的事情应该有效:
#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。
有关详细信息,请参阅 here。
您所以接近解决方案!
template<typename T>
struct Class
{
template <typename O>
Class(O*, typename std::enable_if<std::is_convertible<O*, T*>::value>::type * = nullptr)
{
}
};
你看出区别了吗?参数列表中的 *=
被解析为 multiplication/assignment operator,而不是后跟默认参数的指针类型。因此,语法错误。
这是因为C++解析器被指定在形成token时消耗尽可能多的字符(所谓的最大蒙克规则)。添加 space 会按预期将其拆分为两个单独的标记。