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

C++ 函数从模板参数中获取字段值,而不是直接访问以允许相同信息使用不同的名称,c++,c++11,templates,C++,C++11,Templates,我正在设计一个供内部使用的图书馆 函数可以是 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); } 我知道这个函数的调用代码将从外部API接收数据

我正在设计一个供内部使用的图书馆

函数可以是

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);
}
我知道这个函数的调用代码将从外部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));
}
并使用
AlmostA
的迭代器调用我的函数,而不进行任何转换

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

我在谷歌上到处搜索,找不到任何这样做的代码示例

<>我对C++是比较新的,所以我想如果这个方法可行,这个方法有什么缺陷,为什么它不流行或不使用(我知道一些类似的事情是用STD::交换,但这是一个特定的功能)在C++世界中以统一的方式呈现不同接口的数据的替代方案是什么? 为了让编译器找到getter函数,需要在哪个名称空间中实现它?

您的
doStuffInternal(getA(*it)、getB(*it)、getC(*it))
对我来说似乎很可靠-我会使用一个
结构
模板,对您需要支持的每种类型进行显式专门化

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); }

    // ...
};


最终代码如下所示:

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));
}
模板
void doStuff(开始,结束)
{
适配器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_); 
}
模板
自动a(T&&x)->取消类型(向前型(x.a))
{ 
向前返回(x.a);
}

如果你想做的是一个for-each循环,你可以使用(可能与lambda一起使用)函数内部的内容是不相关的,这只是一个例子。我将对这些数据进行操作,问题是如何以通用方式提供对这些数据的访问,为什么不能将
AlmostA
传递给函数?@Makers\u任何通用接口/算法都必须有一些要求或
概念。在您的情况下,限制
doStuff
函数的使用是否足以接受一个
迭代器
,该迭代器的
值类型
可以传递给
getA
getB
getC
函数,并且如果结构的字段不在您的控制范围内,它具有流
操作符,那么,我认为你提出的方法总体上没有任何错误。你可以使用<代码> Boo::融合< /Cord>使设计更好地提升(没有双关语),但是正如你所说的,你是C++的新手,我可能不会在这个时候推荐它。把代码放到一个专门的结构中有什么好处?@ MaKsSfF:不,你需要明确地指定一个带有回退类型的返回类型。我会编辑我的question@Makers_F:优点是特定类型的所有getter都“组合在一起”,并且所有适配器都有一个公共类型。这可以让您在将来定义一个“概念”,在编译时静态地检查
适配器的特定专门化是否具有所需的所有getter。我明白了。所以我可以启用_if?@Makers_F:没错。您可以有一个编译时布尔值
is\u valid\u adapter
,检查
TAdapter
是否实现了所有必需的getter。然后,当您忘记实现
TAdapter
中的一个getter时,您可以使用
static\u assert
std::enable\u(如果
with
有效)\u adapter
生成更好的错误消息。另一个优点是,您还可以使用继承来拥有某种“回退”适配器类型,或者避免重复某些字段具有相同名称的类型。
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&>{});
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));
}
template <typename T>
auto a(T&& x) -> decltype(forward_like<T>(x.a_))
{ 
    return forward_like<T>(x.a_); 
}