繁体   English   中英

编写二进制文件模板函数

[英]writing Binary File template functions

我已经做了一些函数来将类写入和读取二进制文件。

如果参数是一个类,我只想调用第一个writeElement函数。

然后,我想在一个函数中使用int, double, size_t的其他函数。 必须有一种更好的方法来执行此操作,我不必为所有不同类型创建一个新函数。

template <class T>
inline void writeElement(ostream& out, T target) { target.write(out); }
inline void writeElement(ostream& out, int target) { out.write((char*)&target, sizeof(int)); }
inline void writeElement(ostream& out, double target) { out.write((char*)&target, sizeof(double)); }
inline void writeElement(ostream& out, size_t target) { out.write((char*)&target, sizeof(size_t)); }
inline void writeElement(ostream& out, const string str)
{
    size_t size = str.size();
    writeElement(out, size);
    out.write(&str[0], size);
}
template <class T>
inline void writeElement(ostream& out, vector<T> vector)
{
    size_t size = vector.size();
    writeElement(out, size);

    for (auto &element : vector)
    {
        writeElement(out, element);
    }
}


class Header
{
public:
    string sig;
    double  version;

public:
    void read(istream& in)
    {
        readElement(in, sig);
        readElement(in, version);
    }

    void write(ostream& out)
    {
        writeElement(out, sig);
        writeElement(out, version);
    }
};

然后,我想在一个函数中使用int, double, size_t的其他函数。 必须有一种更好的方法来执行此操作,我不必为所有不同类型创建一个新函数。

您可能希望为此使用“ 特征” 类模板 ,并且有一个功能可以为您完成这项工作。

//Primary templates for every other object
template<typename T, typename = void>
struct WriteHelper{

     static void write(ostream& out, T target){
         target.write(out);
     }
};

//Specialization for integral types
template<typename T>
struct WriteHelper<T, std::enable_if_t<std::is_arithmetic<T>::value >>{

     static void write(ostream& out, T target){
         out.write((char*)&target, sizeof(T));
     }
};

//Specialization for std::string
template<typename T>
struct WriteHelper<T, std::enable_if_t<std::is_same<std::string, T>::value >>{

     static void write(ostream& out, T target){
         size_t size = str.size();
         writeElement(out, size);
         out.write(&str[0], size);
     }
};

并用作:

template<typename T, typename X = std::decay_t<T>>
inline void writeElement(ostream& out, T&& target){
      WriteHelper<X>::write(out, std::forward<T>(target));
}

我想有很多方法可以做到这一点。

我建议在设置constexpr值的自定义类型特征的帮助下使用SFINAE

template <typename>
struct foo { static constexpr std::size_t value { 0U }; };

template <>
struct foo<int> { static constexpr std::size_t value { 1U }; };

template <>
struct foo<double> { static constexpr std::size_t value { 1U }; };

template <>
struct foo<std::size_t> { static constexpr std::size_t value { 1U }; };

template <>
struct foo<std::string> { static constexpr std::size_t value { 2U }; };

因此,您可以使用foo<T>::value的值来启用其他写入功能

template <typename T>
inline typename std::enable_if<0U == foo<T>::value>::type
   writeElement (std::ostream & out, T const & t)
 { std::cout << "generic case" << std::endl; }

template <typename T>
inline typename std::enable_if<1U == foo<T>::value>::type
   writeElement (std::ostream & out, T const & t)
 { std::cout << "int, double, size_t case" << std::endl; }

template <typename T>
inline typename std::enable_if<2U == foo<T>::value>::type
   writeElement (std::ostream & out, T const & t)
 { std::cout << "string case" << std::endl; }

template <typename T>
inline void writeElement (std::ostream & out, std::vector<T> const & v)
 { std::cout << "vector case" << std::endl; }

以下是完整的工作示例

#include <set>
#include <vector>
#include <iostream>
#include <type_traits>

template <typename>
struct foo { static constexpr std::size_t value { 0U }; };

template <>
struct foo<int> { static constexpr std::size_t value { 1U }; };

template <>
struct foo<double> { static constexpr std::size_t value { 1U }; };

template <>
struct foo<std::size_t> { static constexpr std::size_t value { 1U }; };

template <>
struct foo<std::string> { static constexpr std::size_t value { 2U }; };

template <typename T>
inline typename std::enable_if<0U == foo<T>::value>::type
   writeElement (std::ostream & out, T const & t)
 { std::cout << "generic case" << std::endl; }

template <typename T>
inline typename std::enable_if<1U == foo<T>::value>::type
   writeElement (std::ostream & out, T const & t)
 { std::cout << "int, double, size_t case" << std::endl; }

template <typename T>
inline typename std::enable_if<2U == foo<T>::value>::type
   writeElement (std::ostream & out, T const & t)
 { std::cout << "string case" << std::endl; }

template <typename T>
inline void writeElement (std::ostream & out, std::vector<T> const & v)
 { std::cout << "vector case" << std::endl; }

int main ()
 {
   writeElement(std::cout, std::set<int>{});
   writeElement(std::cout, 0);
   writeElement(std::cout, 0.0);
   writeElement(std::cout, std::size_t{});
   writeElement(std::cout, std::string{"0"});
   writeElement(std::cout, std::vector<int>{});
 }

只需将SFINAE用于class,native和其他特殊定义的类型,例如:

    template <typename T, typename std::enable_if < std::is_class<T>::value, void >::type* = nullptr >
inline void writeElement( T  )
{
    std::cout << "Class write" << std::endl;
}

    template <typename T, typename std::enable_if<!std::is_class<T>::value, void>::type* = nullptr>
inline void writeElement( T  )
{
    std::cout << "Native type" << std::endl;
}

template <typename T>
inline void writeElement( const std::vector<T>& )
{
    std::cout << "vector" << std::endl;
}

inline void writeElement( std::string )
{
    std::cout << "string" << std::endl;
}

class A{};

int main()
{
    writeElement( A{} );
    writeElement( 1 );
    writeElement( std::vector<int>{1,2,3,4} );
    writeElement( std::string{"Hallo"});

}

因此,每个“本机类型”都可以使用一个模板函数进行处理。 您还应该查看指针,因为您不能以这种方式处理指针,因为您不能通过指针本身传递长度。

也使用SFINAE并拆分

  1. 具有void write(ostream&)方法的类:

     template <typename T> typename std::enable_if<std::is_same<decltype(&T::write), void(T::*)(ostream&)>::value, void>::type writeElement(ostream& out, T& target) { target.write(out); } 

    注意最好通过引用传递类,以防止复制。

  2. 算术类型( intdoublesize_t等):

     template <typename T> typename std::enable_if<std::is_arithmetic<T>::value, void>::type writeElement(ostream& out, T target) { out.write((char*)&target, sizeof(T)); } 

    如果要包括枚举,请使用std::is_scalar

  3. std::stringstd::vector<T>

     inline void writeElement(ostream& out, const string& str) { const size_t size = str.size(); writeElement(out, size); out.write(str.data(), size); // NOTE: Accessing &str[0] if the `.size() == 0` is *Undefined behavior*, use `std::string::data()` insetad } template <class T> inline void writeElement(ostream& out, const vector<T>& vector) { const size_t size = vector.size(); writeElement(out, size); for (const auto &element : vector) { writeElement(out, element); } } 

    注意如果string s &str[0]的大小为零,则访问它会导致未定义的行为

暂无
暂无

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

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