如何在C++中为整数等内置类型添加成员函数
How to add member function for built-in types such as integer in C++
我正在使用 C++ 实现一些东西,我有一个索引类型的集群,它包括两个成员:一个是整数,另一个是结构,如下所示:
typedef int IndexA_t;
struct IndexB_t { ... };
这里有一个需求,我想为这两种类型添加一个通用函数(假设,命名为fun1()),因为我想将它们传递到一个将调用fun1()的模板函数中,很容易为IndexB_t实现这个,但是对于IndexA_t我很困惑,我怎么能为一个整数引入一个函数成员(内置)类型?我必须实现一个 class 模拟 int 类型吗?确实需要很多不必要的工作(很多操作员...),还有其他方法吗?
非常感谢您的帮助,谢谢。
实现一个行为类似于 int
但可以扩展的类型并不难。
#include <iostream>
class Int
{
int m_i;
public:
Int(int i) : m_i(i) {};
operator int&() { return m_i; }
operator int() const { return m_i; }
};
void func(int) {}
int main()
{
// copy-assignment from int
Int i = 2;
i = 4+15;
// Binding reference
int& x = i;
x = 2;
// Implicit conversion in expression
std::cout << i + 2 << '\n';
// Implicit conversion in parameter
func(i);
}
你可以按照玉米杆的建议去做,并使用 std::begin
和 std::end
所采用的相同技术。它为定义 begin
/end
成员函数的对象提供重载,并为其他类型(在这种情况下为数组)提供重载,在这些类型上使用该函数是有意义的。
在下面的设计示例中,我们有一个 getval
自由函数,它为定义 getval
成员函数的类型提供重载,使用尾随 return 类型来激活 SFINAE .然后对于其他类型,它使用类型特征来确保只允许整数类型,而拒绝所有其他类型,再次通过 enable_if
.
使用 SFINAE
这个例子是设计的,只是为了展示你可以用来实现你需要的任何功能的技术(问题没有详细说明那是什么,所以我必须使用许可证)。在下面的例子中,通过向 IndexB_t
class 添加一个 int 转换运算符显然更容易实现相同的效果,但这不是重点。
#include <iostream>
#include <type_traits>
using namespace std;
/* is_integer type trait */
template<typename T>
using is_integer = is_same<remove_cv_t<T>, int>;
template<typename T>
constexpr bool is_integer_v = is_integer<T>::value;
/* getval function definition */
template<typename T,
typename = enable_if_t<is_integer_v<T>>
>
T getval(T i)
{ return i; }
template<typename T>
auto getval(T& t) -> decltype(t.getval())
{ return t.getval(); }
/* defined types */
typedef int IndexA_t;
class IndexB_t
{
int x;
public:
IndexB_t(int i) : x(i) {}
int getval() const { return x; }
};
// a test struct with no `getval` member function.
struct NoGetVal {};
// driver function
int main()
{
int i = 9;
IndexB_t j = 10;
IndexA_t k = 11;
const int l = 12;
volatile int m = 13;
const volatile int n = 14;
float a = 1.1;
NoGetVal ngv;
cout << getval(i) << '\n';
cout << getval(j) << '\n';
cout << getval(k) << '\n';
cout << getval(l) << '\n';
cout << getval(m) << '\n';
cout << getval(n) << '\n';
// disallowed as not int
//cout << getval(a) << '\n';
// disallowed no `getval` member function
//cout << getval(ngv) << '\n';
}
因此,现在您对整数基元和行为类似整数的对象有了一致的接口。
您可能想要减少对原始类型重载中允许的类型的限制,也许使用 std::is_integral
。由你决定。
这是 c++14,但可以通过使用 enable_if
而不是 enable_if_t
等降级到 c++11。并相应地调整代码。
我正在使用 C++ 实现一些东西,我有一个索引类型的集群,它包括两个成员:一个是整数,另一个是结构,如下所示:
typedef int IndexA_t;
struct IndexB_t { ... };
这里有一个需求,我想为这两种类型添加一个通用函数(假设,命名为fun1()),因为我想将它们传递到一个将调用fun1()的模板函数中,很容易为IndexB_t实现这个,但是对于IndexA_t我很困惑,我怎么能为一个整数引入一个函数成员(内置)类型?我必须实现一个 class 模拟 int 类型吗?确实需要很多不必要的工作(很多操作员...),还有其他方法吗?
非常感谢您的帮助,谢谢。
实现一个行为类似于 int
但可以扩展的类型并不难。
#include <iostream>
class Int
{
int m_i;
public:
Int(int i) : m_i(i) {};
operator int&() { return m_i; }
operator int() const { return m_i; }
};
void func(int) {}
int main()
{
// copy-assignment from int
Int i = 2;
i = 4+15;
// Binding reference
int& x = i;
x = 2;
// Implicit conversion in expression
std::cout << i + 2 << '\n';
// Implicit conversion in parameter
func(i);
}
你可以按照玉米杆的建议去做,并使用 std::begin
和 std::end
所采用的相同技术。它为定义 begin
/end
成员函数的对象提供重载,并为其他类型(在这种情况下为数组)提供重载,在这些类型上使用该函数是有意义的。
在下面的设计示例中,我们有一个 getval
自由函数,它为定义 getval
成员函数的类型提供重载,使用尾随 return 类型来激活 SFINAE .然后对于其他类型,它使用类型特征来确保只允许整数类型,而拒绝所有其他类型,再次通过 enable_if
.
这个例子是设计的,只是为了展示你可以用来实现你需要的任何功能的技术(问题没有详细说明那是什么,所以我必须使用许可证)。在下面的例子中,通过向 IndexB_t
class 添加一个 int 转换运算符显然更容易实现相同的效果,但这不是重点。
#include <iostream>
#include <type_traits>
using namespace std;
/* is_integer type trait */
template<typename T>
using is_integer = is_same<remove_cv_t<T>, int>;
template<typename T>
constexpr bool is_integer_v = is_integer<T>::value;
/* getval function definition */
template<typename T,
typename = enable_if_t<is_integer_v<T>>
>
T getval(T i)
{ return i; }
template<typename T>
auto getval(T& t) -> decltype(t.getval())
{ return t.getval(); }
/* defined types */
typedef int IndexA_t;
class IndexB_t
{
int x;
public:
IndexB_t(int i) : x(i) {}
int getval() const { return x; }
};
// a test struct with no `getval` member function.
struct NoGetVal {};
// driver function
int main()
{
int i = 9;
IndexB_t j = 10;
IndexA_t k = 11;
const int l = 12;
volatile int m = 13;
const volatile int n = 14;
float a = 1.1;
NoGetVal ngv;
cout << getval(i) << '\n';
cout << getval(j) << '\n';
cout << getval(k) << '\n';
cout << getval(l) << '\n';
cout << getval(m) << '\n';
cout << getval(n) << '\n';
// disallowed as not int
//cout << getval(a) << '\n';
// disallowed no `getval` member function
//cout << getval(ngv) << '\n';
}
因此,现在您对整数基元和行为类似整数的对象有了一致的接口。
您可能想要减少对原始类型重载中允许的类型的限制,也许使用 std::is_integral
。由你决定。
这是 c++14,但可以通过使用 enable_if
而不是 enable_if_t
等降级到 c++11。并相应地调整代码。