C++ 将整型参数转发给一个构造函数,将浮点指向另一个构造函数
我有: 不幸的是C++ 将整型参数转发给一个构造函数,将浮点指向另一个构造函数,c++,templates,c++11,constructor-overloading,C++,Templates,C++11,Constructor Overloading,我有: 不幸的是 class C { C(long){...}; C(double){...}; : } (这是相当可怕的,不是吗?整数类型肯定会倾向于使用精度更高的整数参数的构造函数。) 如何将整型参数和浮点参数正确地转发到各自的构造函数 编辑:也许我把问题简单化了。它起源于。我正在包装Python原语,例如Float Long String,将初始化转发到正确的原语非常重要。同时,由于这是一个通用包装,我不希望消费者为了避免内部陷阱而不得不担心类型转换 正如Mik
class C
{
C(long){...};
C(double){...};
:
}
(这是相当可怕的,不是吗?整数类型肯定会倾向于使用精度更高的整数参数的构造函数。)
如何将整型参数和浮点参数正确地转发到各自的构造函数
编辑:也许我把问题简单化了。它起源于。我正在包装Python原语,例如Float Long String,将初始化转发到正确的原语非常重要。同时,由于这是一个通用包装,我不希望消费者为了避免内部陷阱而不得不担心类型转换
正如Mike Seymour指出的,SFINAE提供了一种处理这种情况的技术
极大地感谢FreNoDeC++通道上的DUG64 K:以下的解决方案:
当我明天开始追踪的时候,我会尝试把这些变成一个答案 如何将整型参数和浮点参数正确地转发到各自的构造函数 使用: 这太可怕了,不是吗?整数类型当然应该支持采用更高精度的整数参数的构造函数 该标准遵循一种算法来决定哪个重载函数是最佳匹配的。除其他外,它对“晋升”的排名高于“转化”。这意味着“积分提升”的排名高于“积分转换”,“浮点提升”的排名高于“浮点转换”。但是,“积分转换”的排名并不高于“浮点转换”这是第13.3.3.1.1节标准转换序列中的一个表标准说明了在第4节“标准转换”下可以使用“积分提升”、“积分转换”、“浮点提升”和“浮点转换”的位置。就本答案而言,可以说
int
可以转换为long
而不是升级。int
也可以转换为double
。这就解释了为什么当参数类型为int
时,编译器无法消除重载之间的歧义,我只想让它保持原样,让用户明确知道需要哪种类型的转换。如果您确实希望根据您描述的非标准规则允许隐式转换,那么可以使用SFINAE。类似这样的方法会奏效:
C c1{5L};
C c2{5.0};
#包括
#包括
结构C{
//整数类型的构造函数
模板
C(T,typename std::enable_if::type=0)
{std::cout您可以使用模板构造函数将未声明的类型重定向到您选择的构造函数
假设您希望将long
作为默认值。使用SFINAE,您可以检查类型T
是否可以铸造为long
,然后将其传递给long构造函数
#include <iostream>
#include <type_traits>
struct C {
// Constructor for integer types
template <typename T>
C(T, typename std::enable_if<std::is_integral<T>::value, T>::type=0)
{std::cout << "integral\n";}
// Constructor for floating-point types
template <typename T>
C(T, typename std::enable_if<std::is_floating_point<T>::value, T>::type=0)
{std::cout << "floating\n";}
};
int main() {
C c1{5}; // prints "integral"
C c2{5.0}; // prints "floating"
}
你让编译器猜你是在5之后忘记了L还是a.0。我更喜欢不需要编译器猜的代码,也更喜欢不需要编译器猜的编译器。@gnasher729,我尽量让它简单。C{someInt}怎么样?@Pi:我只需要C{long(someInt)}
或C{double(someInt)}
,取决于调用者想要什么。试图破坏该语言的类型转换规则绝非易事(尽管使用SFINAE很可能会得到你认为需要的东西)。@MikeSeymour为什么这么可怕?
#include <iostream>
#include <type_traits>
struct C {
// Constructor for integer types
template <typename T>
C(T, typename std::enable_if<std::is_integral<T>::value, T>::type=0)
{std::cout << "integral\n";}
// Constructor for floating-point types
template <typename T>
C(T, typename std::enable_if<std::is_floating_point<T>::value, T>::type=0)
{std::cout << "floating\n";}
};
int main() {
C c1{5}; // prints "integral"
C c2{5.0}; // prints "floating"
}
class C
{
public:
C(long l){ std::cout << "long constructor" << std::endl; };
C(double d){std::cout << "double constructor" << std::endl; };
// default constructor which passes values to long
template <typename T,
typename std::enable_if<std::is_convertible<long, T>::value, int>::type = 0>
C(T t) : C(long(t)){};
};
int main() {
C c1(5);
C c2(5.0f);
C c3(5.0L);
C c4(5.0);
return 0;
}
long constructor
long constructor
long constructor
double constructor