C++ 有没有一种方法可以对函数以编程方式返回的引用多次调用该函数-元组动态访问

C++ 有没有一种方法可以对函数以编程方式返回的引用多次调用该函数-元组动态访问,c++,recursion,dynamic,tuples,C++,Recursion,Dynamic,Tuples,出于兴趣,我正在尝试使用动态访问实现可变模板元组类型,我希望避免强制转换和返回boost::any或boost::variant。我要说的是,每个递归继承都存储一个指向自身的指针,并且我能够像这样返回它: ParentType& next() { return *this; } 当我在源代码中编写并进行迭代时,我可以调用它,例如: MyTupleImpl<int, std::string, float> myTuple; myTuple.next().next().

出于兴趣,我正在尝试使用动态访问实现可变模板元组类型,我希望避免强制转换和返回
boost::any
boost::variant
。我要说的是,每个递归继承都存储一个指向自身的指针,并且我能够像这样返回它:

ParentType& next() {
    return *this;
}
当我在源代码中编写并进行迭代时,我可以调用它,例如:

MyTupleImpl<int, std::string, float> myTuple;
myTuple.next().next().next();
我可以在源代码中写下这一点,但如何实现它,使我只传递一个数字n,它就可以在返回的引用上应用函数
next()
n次

我尝试了如下递归:

ParentType* get(int i, int j, OwnType k) {

    std::cout << "j" << j << "i" << i << std::endl;
    if (j < i) {
        j++;
        return k.next().get(i, j, k.next());
    }
    else
    {
        return k.current;
    }
}
设置了它的
ParentType
,但调用next时
ParentType
会更改

我可以想象,返回类型推断是元组不能被动态访问的原因之一。然而,当我调用源代码时,为什么会以编程方式执行此操作呢

myTuple.next().next();
myTuple.next().next();
比如说

我知道这有点困惑,但我希望你们中的一些人能够理解我的意思,并能够帮助我。我很抱歉,当我在C++和模板类方面有点新手时,

为什么在我调用源代码时,这个函数以编程方式工作

myTuple.next().next();
myTuple.next().next();
因为类型在编译时是已知的。没有运行时参数,就像您的
get(inti,intj,OwnType k)
尝试中那样。您的尝试不可能成功,但可以实施以下操作:

template<class... Ts>
template<std::size_t I>
magic_type& MyTupleImpl<Ts...>::get();
// magic_type is not actual code. It is a
// placeholder for a proper implementation
模板
模板
magic_type&MyTupleImpl::get();
//magic_类型不是实际代码。这是一个
//正确实现的占位符
模板参数在编译时是已知的,所以这可以工作。现在我们必须使用模板魔术来找出要返回的正确类型。您将需要使用类似于以下内容的递归帮助器模板(此示例从中修改):

模板
结构元组元素;
//递归案例
模板<标准::大小\u t I,班长,班级。。。尾部>
结构元组元素
:元组_元素{};
//基本情况
模板<班长,班。。。尾部>
结构元组元素{
头型;
};
借助于此,我们可以宣布:

template<class... Ts>
template<std::size_t I>
typename tuple_element<I, Ts...>::type&
MyTupleImpl<Ts...>::get();
模板
模板
typename元组元素::type&
MyTupleImpl::get();
我将把
MyTupleImpl::get
的实现作为练习


警告:此答案中没有以任何方式测试任何代码。

我假设
MyTuple
的基本定义如下:

template <class...>
struct MyTuple;

template <class Head, class... Tail>
struct MyTuple<Head, Tail...> : MyTuple<Tail...> {
    Head data;
};

template <class T>
struct MyTuple<T> {
    T data;
};
get
的返回值是所选重载的返回值。它的类型是所有相关重载的公共类型(正如
std::common_type
将返回的那样)。使用它看起来像这样:

MyTuple<float, int, double> tup;

struct {
    void operator()(float) const { }
    void operator()(int) const { }
    void operator()(double) const { }
} func;

for(std::size_t i = 0; i < 3; ++i)
    tup.get(i, func);
MyTuple-tup;
结构{
void运算符()(浮点)常量{}
void运算符()(int)常量{}
void运算符()(双精度)常量{}
}func;
对于(标准::尺寸\u t i=0;i<3;++i)
tup.get(i,func);
循环的每次迭代都将使用所需的数据调用相应的重载


由于我是stackoverflow的新手,我也希望大家对我的发帖/提问方式提出批评,如标题和标签的选择等,以及发帖方式是否可以接受。谢谢。您的
get
应该是模板(以获取constexpr索引)。正如std::get(tuple)所做的那样。有什么原因不能只使用std::get吗?因为据我所知,我无法在运行时传递索引。此外,我正在实现我自己的元组,它(我假设)不符合使用std::get的要求。函数的返回类型不能依赖于运行时值。好吧,酷!我将仔细研究你的答案,乍一看似乎没有模板参数索引,这意味着这可以用于动态访问?今晚晚些时候我会给你回复,我必须试着理解如何实现。对不起,我有点慢。@BafE。在这段代码中,索引参数名为
I
。哦,我明白了,是的,函数返回类型是tuple\u element::type&。这与std::tuple的std::get的实现非常接近,对吗?@BafE。我从
std::tuple_元素
的cppreference页面复制了
tuple_元素
的实现,只做了一些小的修改。我已经将getter声明为您的成员,但在其他方面,接口基本相同。谢谢@Quentin,刚刚回来。我仍然需要考虑这个问题,例如,我必须检查std::forward和双安培的使用。此外,传递这些函子的使用非常麻烦,我将阅读它们在何处/哪些场景中使用最多。我将给出这个答案,并接受它,因为它似乎接近动态访问。我能问一下你在C++中编程多长时间了吗?再次感谢@巴菲。
&&
/
std::forward
机制称为完美转发。它允许以最通用的方式传递functor,但不是严格要求的(如果不存在副本问题,您可以按值获取
F
,并直接调用
F(数据)
)。我已经学习C++四年了!很高兴提供帮助:)我会打电话给
get
类似
visit\n
apply\n
template <class...>
struct MyTuple;

template <class Head, class... Tail>
struct MyTuple<Head, Tail...> : MyTuple<Tail...> {
    Head data;
};

template <class T>
struct MyTuple<T> {
    T data;
};
template <class Head, class... Tail>
struct MyTuple<Head, Tail...> : MyTuple<Tail...> {
    MyTuple<Tail...> &next() {
        return *this;
    }

    template <class F>
    auto get(std::size_t i, F &&f) {
        return i
            ? next().get(i - 1u, std::forward<F>(f))
            : std::forward<F>(f)(data);
    }

    Head data;
};

template <class T>
struct MyTuple<T> {
    template <class F>
    auto get(std::size_t i, F &&f) {
        assert(!i);
        return std::forward<F>(f)(data);
    }

    T data;
};
MyTuple<float, int, double> tup;

struct {
    void operator()(float) const { }
    void operator()(int) const { }
    void operator()(double) const { }
} func;

for(std::size_t i = 0; i < 3; ++i)
    tup.get(i, func);