我想创建封装基本数字类型的轻量级类型:
struct A { long value; }
struct B { long value; }
struct C { long value; }
...
这样我就可以对每种类型应用通常的算术运算,并带有预期的结果(与内置类型long相比没有任何运行时开销):
A a1 {10};
A a2 {20};
A a3 = a1 + a2:
++a3;
std::cout << a3; // prints "31"
...
但是,我不希望在不同类型之间进行任何(自动)转换,并且我不希望允许混合不同类型的任何算术运算。例如,以下代码不编译:
A a1 {10};
A a2 {20};
B b3 = a1 + a2: // error, cannot convert A to B
a2 += b3; // error, A::operator+=(B) does not exist
...
如果我只想要一种类型,那么所有这一切都会很简单;只需为A类定义适当的操作。但是,如果我尝试对只有名称不同的A,B,C ......等类做同样的事情,它很快就会变得乏味。
我知道我可以使用预处理器宏来生成具有不同名称的多个副本。但是,我想知道是否有更优雅的方法不使用预处理器,并且不需要任何重复的代码。 (C ++ 11特定的解决方案很好。)
答案 0 :(得分:5)
一种方法是模板化类,它作为实体类型的一个实现和类别别名。这看起来如下:
namespace detail {
template<typename Alias>
struct Implementation {
//do everything once
};
}
using A = detail::Implementation<struct DummyA>;
using B = detail::Implementation<struct DummyB>;
using C = detail::Implementation<struct DummyC>;
只要每个类型使用不同的类型作为模板参数,每个类型都将是具有相同实现的唯一类型,并且真实类可以隐藏在用户不应该触摸的内容中。
答案 1 :(得分:4)
快速方法是使用BOOST_STRONG_TYPEDEF定义每种新类型。它将为您实现运营商。当然,这“使用”预处理器宏,但您不必定义它们。 Boost.units以模板方式实现算术类型,但如果要定义自己的系统(在SI系统之外),则需要更多参与。
如果要滚动自己的模板类,那么使每个实例化成为唯一类型变得很重要。有几种方法可以做到这一点。一种方法是为模板提供第二个模板参数(除了“底层类型”)以使实例化成为唯一的。第二个模板参数可以像整数一样简单:
template< class T, int id>
struct strong_typedef {
// your operators here
};
但是,您必须保留以前使用过的整数管理(如果定义分布在不同的位置,这很难)。
或者,您可以引入标记类型作为第二个参数:
template< class T, class Tag>
struct strong_typedef// etc...
struct integerA {};
typedef strong_typedef< long, integerA> MyIntegerAType;
答案 2 :(得分:2)
考虑一下:
#include <iostream>
template <class T,int tag_num=0>
class base{
public:
T val;
base(T val_arg) : val (val_arg) {}
base<T,tag_num>& operator+(const base<T,tag_num>& a)
{
val += a.val;
return *this;
}
};
template <class T,int tag_num>
std::ostream& operator<< (std::ostream& s, const base<T,tag_num>& a)
{
s << a.val;
return s;
}
typedef base<long,1> my_type_1;
typedef base<long,2> my_type_2;
int main()
{
my_type_1 v1(1);
my_type_1 v2(2);
my_type_1 res = v1 + v2;
std::cout << res << std::endl;
my_type_1 r1 = v1;
my_type_2 v3(3);
//my_type_1 r2 = v3; // This is a compilation error
//my_type_1 res2 = v1 + v3; // This is a compilation error
//std::cout << res2 << std::endl;
return 0;
}
答案 3 :(得分:-1)
如果各种类型的实现相同,则可以考虑使用类模板。即使你可以专门为某些类型的模板。只研究这个概念,你就会知道我在说什么。