函数从模板参数中获取字段值,而不是直接访问以允许对相同信息使用不同的名称

Function to get field value from template parameter instead of direct access to allow different names for same information

本文关键字:信息 访问 参数 获取 字段 函数      更新时间:2023-10-16

我正在设计一个内部使用的库。

一个函数可以是

template<typename It>
void doStuff(It begin, It end)
{
// This is example code. The point is to show that I access the data of the iterator
doStuffInternal(it->a, it->b, it->c);
}

这个函数是一个模板,因为我想接受所有类型的迭代器,但我对迭代器产生的类型有特定的期望。

目前,我的代码假设一个对象是用类似的结构传递的

struct A
{
int a;
std::string b;
BigObject   c;
};

我知道这个函数的调用代码将从外部API接收数据,数据看起来像

struct AlmostA
{
int a_;
std::string _b;
AlmostBigObject   cc;
};

现在我不能将这个AlmostA传递给我的函数,我需要将它转换为A(或类似于A的东西),即使所有信息都在AlmostA中,只是名称不同(类型略有不同)。

我想做的是创建一个访问字段的函数

inline int getA(const &A a)
{
return a.a;
}
inline std::string& getB(const &A a)
{
return a.b;
}

等等,然后将我的函数重写为

template<typename It>
void doStuff(It begin, It end)
{
doStuffInternal(getA(*it), getB(*it), getC(*it));
}

然后调用代码可以定义

inline int getA(const &AlmostA a)
{
return a.a_;
}
inline std::string& getB(const &AlmostA a)
{
return a._b;
}

并使用AlmostA的迭代器调用我的函数,而不进行任何转换。

我希望通过这种方式实现的是,调用代码可以定义它们如何提供信息,而不必强制使用具有这些特定字段的结构。

我在谷歌上搜索了一下,找不到任何代码这样做的例子。

我对C++还比较陌生,所以我想知道如果这能起作用,这种方法有什么陷阱,为什么它不受欢迎或不被使用(我知道std::swap也有类似的功能,但这是一个特殊的功能)在C++世界中,有什么可供选择的解决方案可以用不同的接口以统一的方式呈现数据?

getter函数需要在哪个命名空间中实现,以便编译器找到它们?

您的doStuffInternal(getA(*it), getB(*it), getC(*it))对我来说似乎很可靠-对于您需要支持的每种类型,我都会使用带有显式专用化struct模板。

template <typename T>
struct adapter;
template <>
struct adapter<A>
{
template <typename T>
decltype(auto) a(T&& x) { return forward_like<T>(x.a); }
template <typename T>
decltype(auto) b(T&& x) { return forward_like<T>(x.b); }
// ...
};
template <>
struct adapter<AlmostA>
{
template <typename T>
decltype(auto) a(T&& x) { return forward_like<T>(x.a_); }
template <typename T>
decltype(auto) b(T&& x) { return forward_like<T>(x._b); }
// ...
};

使用decltype(auto)作为返回类型并且forward_like允许您保留x的成员的值类别:

static_assert(std::is_same<decltype(adapter<A>::a(A{})), int&&>{});
A lvalue{};
static_assert(std::is_same<decltype(adapter<A>::a(lvalue)), int&>{});
const A const_lvalue{};
static_assert(std::is_same<decltype(adapter<A>::a(const_lvalue)), const int&>{});

wandbox示例(价值类别传播)


最后的代码看起来像这样:

template<typename It>
void doStuff(It begin, It end)
{
adapter<std::decay_t<decltype(*it)>> adp;
doStuffInternal(adp.a(*it), adp.b(*it), adp.c(*it));
}

在C++11中,需要使用尾部返回类型显式指定返回类型。示例:

template <typename T>
auto a(T&& x) -> decltype(forward_like<T>(x.a_))
{ 
return forward_like<T>(x.a_); 
}