c++templatesvisual-c++subtypec++-templates

How to modify a templated sub-type


I'm porting an old C++ code library that used to compile under VS2005, but is giving me trouble in VS2022. The library supports a kind of system to serialize objects to a stream, and to restore them from a stream. It is designed so that you can pass to it a LoadArchive or a SaveArchive object, and then write a single template function for your class that will accept either an LoadArchive or an SaveArchive : this way a single function (written once) will either read or write the object from the file.

class LoadArchive {
 public:
   template<class F>
   void operator()(char const* fieldName, F& field ); // read field from archive

   template<typename Data> struct DataRefType { typedef Data& type; };
};

class SaveArchive {
 public:
   template<class F>
   void operator()(char const* fieldName, F const& field); // write field to archive

   template<typename Data> struct DataRefType { typedef Data& type; };
};

// This allows to write a single transfer function for an object as follows
struct ObjectX {
   int         AA;
   std::string BB;
};

template<class Archive> // read from LoadArchive or write to SaveArchive
void transfer(Archive& arc, typename Archive::DataRefType<ObjectX>::type d) //###
{
    arc("AA",d.AA); // nicely works for read & write
    arc("BB",d.BB);
}

This used to compile, but with VS2022 we now get an error on the declaration at //### stating:

Error C2988 unrecognizable template declaration/definition

Essentially, the "DataRefType" sub-structure is used to provide the correct parameter type ( Object const& or Object& ) depending on whether a save or load operation is being invoked.

The current syntax isn't ideal, but it was convenient and used to work, and I'd like to avoid having to write two versions of the 'transfer' function for the many Object types in my code base.

Is there a working (/ better) idiom for me to 'adapt' the type of the d parameter to the transfer function above depending on the type of transfer being invoked?

Your help is sincerely appreciated !


Solution

  • Your new MSVC is correct.
    clang gives a more useful error here (see on Godbolt):

    error: use 'template' keyword to treat 'DataRefType' as a dependent template name
    

    I.e. you need to tell the compiler that DataRefType is a template:

    template<class Archive> // read from LoadArchive or write to SaveArchive
    //--------------------------------------------vvvvvvvv------------------------------
    void transfer(Archive& arc, typename Archive::template DataRefType<ObjectX>::type d) //###
    {
        arc("AA", d.AA); // nicely works for read & write
        arc("BB", d.BB);
    }
    

    Live demo