简体   繁体   English

如何强类型定义非基本类型?

[英]How do I strongly typedef non-primitive types?

Observe the following program in which a function accepts both the expected type and any type that is a typedef of that type. 请注意以下程序,其中函数接受期望类型和作为该类型的typedef的任何类型。

//a user defined type
class Widget{};

//a function that takes a Widget
void function (Widget w){}

int main(){

    //make a typedef (this is C++11 syntax for a typedef. It's the same thing)
    using Gadget = Widget;

    //make the two "different types" (well.. they're not really different as you will see)
    Widget w;
    Gadget g;

    //call a function that should ONLY accept Widgets
    function(w); //works (good)
    function(g); //<- works (I do not want this to compile though)

}

As you can see, a typedef does not actually distinguish a new type. 如您所见,typedef实际上并不区分新类型。 I thought instead to inherit from the type: 我想改为从类型继承:

//inherit instead
class Gadget: public Widget{};

//make the two "different types"
Widget w;
Gadget g;

//call the function that should ONLY accept widgets
function(w); //works (good)
function(g); //<- works (I do not want this to compile though)

Same problem. 同样的问题。
Looking at boost, I thought to try a strong typedef: 看看提升,我想尝试一个强大的typedef:

#include <boost/serialization/strong_typedef.hpp>

//a user defined type
class Widget{};

//a function that takes the user defined type
void function (Widget w){}

int main(){

    //try to strongly typedef
    BOOST_STRONG_TYPEDEF(Widget, Gadget)

    //make the two "different types"
    Widget w;
    Gadget g;

    //call the function that should ONLY accept widgets
    function(w);
    function(g);

}

compile errors: 编译错误:

In member function ‘bool main()::Gadget::operator==(const main()::Gadget&) const’:
error: no match for ‘operator==’ (operand types are ‘const Widget’ and ‘const Widget’)
  BOOST_STRONG_TYPEDEF(Widget, Gadget)
  ^
In member function ‘bool main()::Gadget::operator<(const main()::Gadget&) const’:
error: no match for ‘operator<’ (operand types are ‘const Widget’ and ‘const Widget’)
  BOOST_STRONG_TYPEDEF(Widget, Gadget)
  ^

Apparently BOOST_STRONG_TYPEDEF only works on primitive types. 显然BOOST_STRONG_TYPEDEF仅适用于基本类型。
I tried to do inheritance again, but stop the implicit conversion: 我试图再次继承,但停止隐式转换:

//I want the functionality, but these are NOT the same type!
class Gadget: public Widget{
    operator Widget() = delete;
};

That did not work either. 那也行不通。

Questions: 问题:

  1. Why does boost strong_typedef only work on primitive types? 为什么boost strong_typedef只适用于原始类型?
  2. How can I 'typedef' a non-primitive type to get functionality similar to boost strong_typef? 我如何'typedef'非原始类型以获得类似于boost strong_typef的功能?

Basically you need two unrelated classes with the same behavior. 基本上你需要两个具有相同行为的无关类。 I would use a parametrized template for that: 我会使用参数化模板:

template<int tag> class WidgetGadget { ... };
typedef WidgetGadget<0> Widget;
typedef WidgetGadget<1> Gadget;

BOOST_STRONG_TYPEDEF actually assumes that types are equatable ( == ), assignable ( = ) and less-than-comparable ( < ). BOOST_STRONG_TYPEDEF实际上假设类型是equatable( == ),assignable( = )和less-than-comparative( < )。

If your type isn't, then the macro results in code that doesn't compile, as you have witnessed. 如果您的类型不是,那么宏会导致代码无法编译,如您所见。 You can roll your own macro or provide implementations for the required operations. 您可以滚动自己的宏或提供所需操作的实现。

You can find a CUSTOM_STRONG_TYPEDEF in this answer from februari 2012: How to use comparison operators on variant with contained types? 您可以在2012年2月的答案中找到CUSTOM_STRONG_TYPEDEF如何在变量上使用包含类型的比较运算符? , which explicitly avoids getting the default comparison behaviour ,明确避免获取默认比较行为

Update Made the example more explicit for your use case, see it Live On Coliru 更新使您的用例更加明确, 请参阅Live On Coliru

//a user defined type
class Widget{};
class Frobnicator{};

/////////////////////////////////////////////////////
// copied and reduced from boost/strong_typedef.hpp
#define CUSTOM_STRONG_TYPEDEF(T, D)                                 \
struct D                                                            \
    /*: boost::totally_ordered1< D           */                     \
    /*, boost::totally_ordered2< D, T        */                     \
    /*> >                                    */                     \
{                                                                   \
    T t;                                                            \
    explicit D(const T t_) : t(t_) {};                              \
    D(){};                                                          \
    D(const D & t_) : t(t_.t){}                                     \
    D & operator=(const D & rhs) { t = rhs.t; return *this;}        \
    D & operator=(const T & rhs) { t = rhs; return *this;}          \
    explicit operator const T & () const {return t; }               \
    explicit operator T & () { return t; }                          \
    /*bool operator==(const D & rhs) const { return t == rhs.t; } */\
    /*bool operator<(const D & rhs) const { return t < rhs.t; }   */\
};

CUSTOM_STRONG_TYPEDEF(Widget, Gadget)
CUSTOM_STRONG_TYPEDEF(Frobnicator, Normalcy)

void acceptWidget(Widget){}
void acceptGadget(Gadget){}
void acceptFrobnicator(Frobnicator){}
void acceptNormalcy(Normalcy){}

int main(){

    //make the two "different types" (well.. they're not really different as you will see)
    Widget w;
    Gadget g;

    //call a function that should ONLY accept Widgets
    acceptWidget(w); //works (good)
    acceptGadget(g);

    //acceptWidget(g); // Error
    //acceptGadget(w); // Error
    // but we can enjoy conversions if we summon them
    acceptWidget(static_cast<Widget&>(g));

    Frobnicator f;
    Normalcy n;
    acceptFrobnicator(f);
    acceptNormalcy(n);

}

也许你可以使用私有继承,有些using s?

class Gadget : Widget { using Widget::Widget; using Widget::foo; ... };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM