【问题标题】:Creating several mutually incompatible numerical types [duplicate]创建几种相互不兼容的数字类型[重复]
【发布时间】:2013-08-15 11:07:36
【问题描述】:

我想创建封装原始数值类型的轻量级类型:

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 特定的解决方案很好。)

【问题讨论】:

  • 如果您的意思是它们都具有相同的实现,但是是离散类型,您可以执行template&lt;typename T&gt; struct Real {/*implement*/}; using A = Real&lt;struct Dummy&gt;; using B = Real&lt;struct Dummy&gt;; 之类的操作。
  • 根据您想要的这些类型的数量,您可能可以为您的类使用模板和std::enable_if 以及特殊的类型特征结构。
  • @chris:如果您每次都使用相同的struct Dummy,您最终不会得到兼容的类吗?
  • @MatthieuM.,我很确定它每次都会创建一个新的。 1秒。更新:是的,你是对的。它们是相同的,所以每个新的都需要一个不同的名称(cough DummyA, DummyB)。
  • @MatthieuM.,啊,问题已经找到了。我想你会喜欢的:stackoverflow.com/questions/14232293/…

标签: c++ c++11


【解决方案1】:

一种方法是使用模板类作为该类的一个实现和类型别名,用于您的真实类型。这可能如下所示:

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>;

只要每个使用不同的类型作为模板参数,每个都是具有相同实现的唯一类型,并且真正的类可以隐藏在用户不应该接触的地方。

【讨论】:

    【解决方案2】:

    一种快速的方法是使用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;
    

    【讨论】:

    • 为什么第一个模板参数不足以产生唯一类型?
    • @LightnessRacesinOrbit,OP 希望拥有具有相同类型的不同类型,例如long,作为它们的值类型。
    • 哦,好的。我没有意识到这一点,因为它太愚蠢了。
    【解决方案3】:

    只是考虑一下:

    #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;
    }
    

    【讨论】:

      【解决方案4】:

      如果您的实现跨类型相同,您可以考虑使用类模板。甚至您可以为某些类型专门化模板。只要研究一下这个概念,你就会知道我在说什么。

      【讨论】:

      • Just research the concept and you will know what I am talking about 不是一个有用的答案
      猜你喜欢
      • 1970-01-01
      • 2012-10-22
      • 2020-01-16
      • 1970-01-01
      • 2018-06-11
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      • 2020-07-07
      相关资源
      最近更新 更多