1

I currently have the following code:

template< class Obj, class ObjResult >
CLStatus convertObjToResult2( const Obj & xFrom, ObjResult & xTo )
{
    CLStatus eStatus = CLSTATUS_SUCCESS;
    switch ( xTo.eType )
    {
        case CEPTFull:
            xTo.xData.xFull = xFrom;
            break;
        case CEPTBrief:
            eStatus = Convert( xFrom, xTo.xData.xBrief );
            break;
        default:
            eStatus = CLSTATUS_INVALIDPROJECTIONTYPE;
    }
    return eStatus;
}

template< class Obj, class ObjResult >
CLStatus convertObjToResult1( const Obj & xFrom, ObjResult & xTo )
{
    CLStatus eStatus = CLSTATUS_SUCCESS;
    switch ( xTo.eType )
    {
        case CEPTFull:
            xTo.xData.xFull = xFrom;
            break;
        default:
            eStatus = CLSTATUS_INVALIDPROJECTIONTYPE;
    }
    return eStatus;
}

All ObjResults have an xFull, but only some have an xBrief, where xData is a union. This resulted in me writing the two different templates above, but it would be great if I could somehow have just one template.

I can't simply use convertObjToResult2, since it will fail to compile with object types that do not have an xBrief. I looked at this answer to see if it would help, but I don't understand at all what it's doing.

Community
  • 1
  • 1
Jesse Jashinsky
  • 10,313
  • 6
  • 38
  • 63

1 Answers1

2

Since C++ does not and won't have a static if feature, you need a work around.

If you can't overload Convert as you said in comments, I thought of a layer above it which can be specialized depending on if ObjResult has the member or not.

template <class Obj, class ObjResult, class = void>
struct ConvertIfHasBrief {
  static auto Convert(Obj const &, ObjResult &) -> CLStatus  {
      return {};// dymmy value, not used
   }
};

template <class Obj, class ObjResult>
struct ConvertIfHasBrief <Obj, ObjResult,
                          std::void_t<decltype(std::declval<ObjResult>().xData.xBrief)>> {
  static auto Convert(Obj const &xFrom, ObjResult &xTo) {
    return ::Convert(xFrom, xTo.xData.xBrief);
  }
};



template< class Obj, class ObjResult>
CLStatus convertObjToResult( const Obj & xFrom, ObjResult & xTo )
{
    CLStatus eStatus = CLSTATUS_SUCCESS;
    switch ( xTo.eType )
    {
        case CEPTFull:
            xTo.xData.xFull = xFrom;
            break;
        case CEPTBrief:
                eStatus = ConvertIfHasBrief<Obj, ObjResult>::Convert(xFrom, xTo);
            break;
        default:
            eStatus = CLSTATUS_INVALIDPROJECTIONTYPE;
    }
    return eStatus;
}

std::void_t is not yet part of the standard, but the implementation is simple and can be found on the linked page. Just be sure not to declare it on the std namespace.

proof it works

bolov
  • 72,283
  • 15
  • 145
  • 224
  • i don't thing this is correct, since `if (hasXBrief)` is not checked while compile time. – user1810087 Jan 11 '16 at 23:31
  • That doesn't handle the compile error at `xTo.xData.xBrief` – Jesse Jashinsky Jan 11 '16 at 23:32
  • @JesseJ you said `xData` is a union. Then it has both members. Why would it be a compile error? – bolov Jan 11 '16 at 23:33
  • 1
    Because some ObjResults do not have xBrief, just xFull. – Jesse Jashinsky Jan 11 '16 at 23:34
  • @JesseJ `ObjResults` is a class. All objects of this class have the same members. What am I missing? – bolov Jan 11 '16 at 23:35
  • 1
    ObjResult is a templated class. It represents about a 100 different possible classes. They do not all have the same members. – Jesse Jashinsky Jan 11 '16 at 23:39
  • @JesseJ sorry, my bad. Editing – bolov Jan 11 '16 at 23:39
  • You still have a mismatch: ConvertIfHasXData vs ConvertIfHasBrief. Also your classes are attempting to be specialized based on the template parameters to a member function.... I think you have the big picture right idea, but every detail here is dead wrong. – Mooing Duck Jan 11 '16 at 23:53
  • @MooingDuck ty for the `ConvertIfHasData`. The specialization on struct is intentional as I try to avoid specializing functions. Hope it is not wrong. Can't test it in a compiler right now. – bolov Jan 11 '16 at 23:55
  • @MooingDuck ty very much. What I meant (read: should have said) is I don't have the patience to write the test case and to debug the program online. But your code helped and motivated me. Ty – bolov Jan 12 '16 at 00:50
  • I had to change `static auto Convert( Obj const &xFrom, ObjResult &xTo )` to `static auto Convert( Obj const &xFrom, ObjResult &xTo ) -> CLStatus` and remove the `std::` from `void_t`, but it compiled. Thanks! It works! Although I'm not sure this is compatible with our older version of Solaris. – Jesse Jashinsky Jan 12 '16 at 16:26
  • @JesseJ It can be done in all school C++ (except for `decltype` but ther are compiler extensions for that, like gcc's `typeof`) – bolov Jan 12 '16 at 17:49