接受const和非const数据的通用函数以及相关函数

时间:2018-12-18 13:21:24

标签: c++ templates c++14

要想更好地理解问题标题,请考虑以下代码:

template <typename T>
void write(const T& /*data*/)
{
    // use data as const
}

template <typename T>
void read(T& /*data*/)
{
    // modify data
}

struct S { 
    int a;
    int b;
    // a lot of primitive types here
};

void output(const S& s)
{
    write(s.a);
    write(s.b);
    // ...
}

void input(S& s)
{
    read(s.a);
    read(s.b);
    // ...
}

int main()
{
    S s;
    input(s);
    output(s);
}

我有writeread函数,可以处理原始数据,例如intdouble等。我有几种结构类型,例如S,其中包含很多原始数据成员的类型,我需要通过相应的函数inputoutput输入和输出此类类型(不同类型有很多重载)。如您所见,outputinput函数的内容基本相同,只是内部函数和类型常量性不同。我想做一些通用的(模板)函数use,以消除input / output函数中的重复代码。

我认为模板签名如下(但我可能会错过一些东西):

template <typename F, typename T>
void use(T& t) { ... }

所以我可以像这样从use / input调用output函数:

use<write, S>(s); // in output function
use<read, S>(s);  // in input fuction

如何归档这种(或类似的)行为以消除重复的代码?我正在使用C ++ 14。

3 个答案:

答案 0 :(得分:1)

template <typename S, typename F>
void use(S&& s, F&& f)
{
    f(s.a);
    f(s.b);
    f(s.c);
}

用法:

use(s, [](const auto& x){ write(x); });
use(s, [](auto& x)      { read(x); });

live example on wandbox.org


如果您需要多种类型:

template <typename S, typename Target>
using EnableFor = std::enable_if_t<std::is_same_v<std::decay_t<S>, Target>>;

template <typename S, typename F>
auto use(S&& s, F&& f) -> EnableFor<S, S0>
{
    f(s.a);
    f(s.b);
    f(s.c);
}

template <typename S, typename F>
auto use(S&& s, F&& f) -> EnableFor<S, S1>
{
    f(s.d);
    f(s.e);
    f(s.f);
}

用法:

int main()
{
    S0 s0; 
    use(s0, [](const auto& x){ write(x); });
    use(s0, [](auto& x)      { read(x); });

    S1 s1;
    use(s1, [](const auto& x){ write(x); });
    use(s1, [](auto& x)      { read(x); });
}

live example on wandbox.org

答案 1 :(得分:0)

您可以定义所使用模板的接口:

template<class M, class S>
void use(S &&s) {
    M::method(s.a);
    M::method(s.b);
};

然后实施它:

template <typename T>
void write(const T& /*data*/)
{
    // use data as const
}

struct writer {
    template <typename T>
    static void method(const T& t)
    {
        write(t);
    }
};

现在您可以使用它:

use<writer>(s);

对于read,它是相同的:

struct reader {
    template <typename T>
    static void method(T& t)
    {
        read(t);
    }
};

use<reader>(s);

答案 2 :(得分:0)

我相信我了解您想要什么,但这是不可能的。当前,尚无办法在所有类的C ++通用流中实现。人们将需要访问诸如类具有的字段数,它们的相对地址以及编译时间类型之类的信息。

当前,他们致力于将其添加到C ++已有多年,请寻求Reflection TS。据我所知,它不会为C ++ 20做好准备。

但是,您可以组织代码,以使每种读/写方法都易于实现。例如:

class A : public B, public C
{
   private:
   vector<int> m_v;
   int m_x;
};

然后将实现写入为

template<>
void write(const A& a)
{
     write((const B&)a);
     write((const C&)a);
     write(a.m_v);
     write(a.m_x);
}

对于诸如std::vector<T>之类的常见数据结构,则通过write<T>实现写入。这需要时间,但是使其技术化并使用重定向可以节省大量代码和时间。

(您需要将write设为朋友功能或成员功能,以使其可以访问私人成员)