【问题标题】:How do I strongly typedef non-primitive types?我如何强类型定义非原始类型?
【发布时间】:2014-04-21 22:35:41
【问题描述】:

观察下面的程序,其中一个函数既接受预期的类型,也接受属于该类型的 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)

}

如您所见,typedef 实际上并不区分新类型。我想改为从类型继承:

//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)

同样的问题。
看着boost,我想尝试一个强大的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);

}

编译错误:

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)
  ^

显然 BOOST_STRONG_TYPEDEF 仅适用于原始类型。
我尝试再次进行继承,但停止隐式转换:

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

那也没用。

问题:

  1. 为什么 boost strong_typedef 只对原始类型起作用?
  2. 如何“typedef”非原始类型以获得类似于 boost strong_typef 的功能?

【问题讨论】:

  • 我想我会class WidgetBase,然后class Widget: public WidgetBase; class Gadget: public WidgetBase.
  • @zneak:BOOST_STRONG_TYPEDEF 就是这样做的。
  • @Deduplicator 查看实现 strong_typedef 使用成员而不是继承。
  • strong_typedef 并不是只适用于原始类型,而是要求参数类型是完全有序的(operator==,operator&lt;)你可以提供它们或者只使用 strong_typedef 中的代码减去排序。
  • 你想要一个类型Gadget,它类似于Widget,但不像Widget。退后一步想想你真正想要声明的内容是否会有所帮助?

标签: c++ c++11 boost types typedef


【解决方案1】:

基本上,您需要两个具有相同行为的不相关类。我会为此使用参数化模板:

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

【讨论】:

    【解决方案2】:

    BOOST_STRONG_TYPEDEF 实际上假定类型是可相等的 (==)、可分配的 (=) 和小于可比的 (&lt;)。

    如果您的类型不是,那么宏会导致代码无法编译,正如您所见证的那样。您可以推出自己的宏或提供所需操作的实现。

    您可以在 2012 年 2 月的这个答案中找到 CUSTOM_STRONG_TYPEDEF:How to use comparison operators on variant with contained types?,它明确避免获得默认比较行为

    更新为您的用例做了更明确的示例,查看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);
    
    }
    

    【讨论】:

    • 要解决原始问题中给出的问题,需要注释掉运算符 T 的最后两种方法。这是一个不错的解决方案,但必须重新编写再次处理不同的类型,因此必须对宏进行唯一命名。
    • 我不明白你的意思。我主要只是引用了另一个答案。但是,进行explicit 的转换就可以了,而且,不,你不必一遍又一遍地写这个吗?更新了我的答案。看到它Live On Coliru**
    • 啊!我现在看到了明确的。我添加到您的示例程序中以说明此宏如何仅用于一种类功能。因此,我必须编写多个宏来处理这些不同的情况。 coliru.stacked-crooked.com/a/8d80373ebd596c61
    • @TrevorHickey 哦。好。我现在明白了,但这从来都不是你问题的一部分:S。教训:拥有需求对于获得正确的解决方案至关重要。另外,请注意,与其他任何答案不同,我也确实回答了您问题的第一部分 (1.)。我想你会想要使用 grep 的答案,但这不是你问的:/
    【解决方案3】:

    也许您可以使用私有继承和一些usings?

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

    【讨论】:

    • 我认为这是一个不错的解决方案,假设没有太多方法或数据成员可以列出。
    猜你喜欢
    • 1970-01-01
    • 2019-05-08
    • 2011-06-12
    • 2019-05-17
    • 2014-07-06
    • 1970-01-01
    • 2019-11-20
    • 2020-02-11
    • 1970-01-01
    相关资源
    最近更新 更多