在C ++中,我希望有一个类,其构造函数如下:
class A {
explicit A(A* other) { ... }
explicit A(intptr_t other) { ... }
};
问题在于用户是否使用
进行初始化A a(0);
然后,在64位系统上,编译器会抱怨它不知道0
是否应转换为A*
或intptr_t
,这是公平的。由于我希望这个简单的符号起作用,我添加了以下构造函数:
explicit A(int a) { assert(a==0); ... }
断言是因为这是唯一有意义的整数。现在,问题出现在32位系统中,其中intptr_t
实际上是...... int
!所以现在,系统抱怨有两个构造函数采用相同的参数类型(这也是公平的)。
所以我的问题是:预处理器是否有办法检测intptr_t
实际上是int
,在这种情况下,不能用int
编译构造函数。或者,是否有另一种方法可以使A a(0)
符号无效,而无需使用int
添加构造函数,但不删除两个第一个构造函数中的任何一个(并且不会使它们隐式)。
答案 0 :(得分:3)
像
这样的东西#if INTPTR_MAX == INT_MAX
可能会做到这一点,但它仍然会导致long
和{{}}
int
大小相同,ptrint_t
是long
的typedef。
另一种可能性(但不知道你是否可以使用它)
将使用uintptr_t
,而不是intptr_t
。
除此之外:预处理器不知道类型,所以问题
在那里无法解决。你将不得不使用某种元编程
技巧:使用,使int
构造函数成为模板
boost::enable_if
仅在参数类型为int
时激活它。
如果ptrint_t
为int
,则激活的函数永远不会
使用过,因为它永远不会比非模板更好
具有相同签名的功能。如果ptrint_t
不是int
,那么。{
当参数具有类型时,模板实例化将是更好的匹配
int
。 (请注意,我自己从未尝试过这种方式:听起来像我这样
应该是可能的,但我对boost::enable_if
并不熟悉
一定要。)
答案 1 :(得分:1)
为什么不简单地实现一个无参数的构造函数,就好像other
0
一样?如果由于某种原因你不想,我建议使用类型特征,前提是你可以访问C ++ 11编译器或者提升:
class A {
public:
explicit A(A* other) { ... }
explicit A(intptr_t other) { ... }
template <class T>
explicit A(T other)
{
static_assert(std::is_convertible<T, intptr_t>::value, "Could not convert value to intptr_t");
static_assert(std::is_integral<T>::value, "Argument must be integral");
intptr_t p = other;
...
}
};
您可以摆脱静态断言和类型检查,但是当您执行以下操作时,您将收到警告(取决于您的警告级别,甚至可能会变成错误)而不是编译器错误:
A a(0.0f);
答案 2 :(得分:0)
我认为最简单的方法是声明所有6个构造函数(int,long,long long和它们的无符号变体),而不是使用intptr_t。
答案 3 :(得分:-1)
还有另一种方法可以使
A a(0)
符号有效
只需介绍一个template
构造函数。
class A {
public:
template<typename T>
explicit A (T t) { assert(t==0); } // explicit matters ?
explicit A(A* other) { ... }
explicit A(intptr_t other) { ... }
};
这将解决您的32位和64位问题!
答案 4 :(得分:-1)
您还可以传递一个参数,该参数决定调用哪个参数:
struct TakePtr{};
struct TakeInt{};
class A {
A(A* other, const TakePtr&) { ... }
A(intptr_t other, const TakeInt&) { ... }
};
这样你可以确定调用哪个构造函数:
A a2( 0, TakeInt() ); // calls the 2nd constructor, taking int
A a1( &a2, TakePtr() ); // calls the 1st constructor, taking a pointer