C++11 std::get on std::tuple导致可变参数减少为零,并出现不完整的类型错误

C++11 std::get on std::tuple导致可变参数减少为零,并出现不完整的类型错误,c++11,gcc,variadic-templates,stdtuple,C++11,Gcc,Variadic Templates,Stdtuple,以下代码生成了大量编译器错误: /// Uses template recursion to bind all args template<std::size_t N, typename... Args> class Binder { public: Binder(Sqlite3StatementBase &s, std::tuple<Args...> &tup) { Binder<N - 1, Args...>

以下代码生成了大量编译器错误:

/// Uses template recursion to bind all args
template<std::size_t N, typename... Args> class Binder
{
public:
    Binder(Sqlite3StatementBase &s, std::tuple<Args...> &tup)
    {
        Binder<N - 1, Args...> b(s, tup);
        s.bind(N + 1, std::get<N, Args...>(tup)); // Line 182
    }
};

/// Specialization of Binder to end recursion at 0
template<typename... Args> class Binder<0, Args...>
{
public:
    Binder(Sqlite3StatementBase &s, std::tuple<Args...> &tup)
    {
        s.bind(1, std::get<0, Args...>(tup));
    }
};
///使用模板递归绑定所有参数
模板类活页夹
{
公众:
活页夹(Sqlite3StatementBase&s,std::tuple&tup)
{
粘合剂b(s,tup);
s、 绑定(N+1,std::get(tup));//第182行
}
};
///绑定器的专门化以结束0处的递归
模板类活页夹
{
公众:
活页夹(Sqlite3StatementBase&s,std::tuple&tup)
{
s、 bind(1,std::get(tup));
}
};
第一批错误包括:

In file included from /usr/include/c++/6/bits/unique_ptr.h:37:0,
             from /usr/include/c++/6/condition_variable:43,
             from /home/tony/htpc/Dev/logi/src/db/logi-db.h:22,
             from /home/tony/htpc/Dev/logi/src/db/logi-sqlite.h:26,
             from /home/tony/htpc/Dev/logi/src/db/logi-sqlite.cpp:24:
/usr/include/c++/6/tuple: In instantiation of ‘class std::tuple_element<1ul, std::tuple<unsigned int> >’:
/usr/include/c++/6/tuple:1228:12:   recursively required from ‘class std::tuple_element<2ul, std::tuple<unsigned int, unsigned int> >’
/usr/include/c++/6/tuple:1228:12:   required from ‘class std::tuple_element<3ul, std::tuple<unsigned int, unsigned int, unsigned int> >’
/usr/include/c++/6/utility:106:69:   required by substitution of ‘template<long unsigned int __i, class _Tp> using __tuple_element_t = typename std::tuple_element::type [with long unsigned int __i = 3ul; _Tp = std::tuple<unsigned int, unsigned int, unsigned int>]’
/usr/include/c++/6/tuple:1270:5:   required by substitution of ‘template<long unsigned int __i, class ... _Elements> constexpr std::__tuple_element_t<__i, std::tuple<_Elements ...> >&& std::get(std::tuple<_Elements ...>&&) [with long unsigned int __i = 3ul; _Elements = {unsigned int, unsigned int, unsigned int}]’
/home/tony/htpc/Dev/logi/src/db/logi-sqlite.h:182:47:   required from ‘logi::Sqlite3Database::Binder<N, Args>::Binder(logi::Sqlite3Database::Sqlite3StatementBase&, std::tuple<_Elements ...>&) [with long unsigned int N = 3ul; Args = {unsigned int, unsigned int, unsigned int}]’
/home/tony/htpc/Dev/logi/src/db/logi-sqlite.h:238:71:   required from ‘void logi::Sqlite3Database::Sqlite3Statement<Args>::prepare_row(logi::Sqlite3Database::Sqlite3Statement<Args>::Tup&) [with Args = {unsigned int, unsigned int, unsigned int}; logi::Sqlite3Database::Sqlite3Statement<Args>::Tup = std::tuple<unsigned int, unsigned int, unsigned int>]’
/home/tony/htpc/Dev/logi/src/db/logi-sqlite.h:231:28:   required from ‘void logi::Sqlite3Database::Sqlite3Statement<Args>::execute(typename logi::Sqlite3Database::Sqlite3Statement<Args>::Parent::ArgsVector&) [with Args = {unsigned int, unsigned int, unsigned int}; typename logi::Sqlite3Database::Sqlite3Statement<Args>::Parent::ArgsVector = std::vector<std::tuple<unsigned int, unsigned int, unsigned int>, std::allocator<std::tuple<unsigned int, unsigned int, unsigned int> > >]’
/home/tony/htpc/Dev/logi/src/db/logi-sqlite.cpp:354:1:   required from here
/usr/include/c++/6/tuple:1228:12: error: invalid use of incomplete type ‘class std::tuple_element<0ul, std::tuple<> >’
在/usr/include/c++/6/bits/unique\u ptr.h:37:0中包含的文件中,
来自/usr/include/c++/6/condition_变量:43,
from/home/tony/htpc/Dev/logi/src/db/logi db.h:22,
from/home/tony/htpc/Dev/logi/src/db/logi sqlite.h:26,
from/home/tony/htpc/Dev/logi/src/db/logi-sqlite.cpp:24:
/usr/include/c++/6/tuple:在“class std::tuple_元素”的实例化中:
/usr/include/c++/6/tuple:1228:12:从“class std::tuple_元素”递归地需要
/usr/include/c++/6/tuple:1228:12:必须来自“class std::tuple_元素”
/usr/include/c++/6/utility:106:69:替换“使用uu-tuple\u元素的模板u t=typename std::tuple\u元素::type[带长无符号int uu i=3ul;_-Tp=std::tuple]时需要”
/usr/include/c++/6/tuple:1270:5:替换“template constepr std::uu tuple_element_t&&std::get(std::tuple&)[带长无符号int u i=3ul;_Elements={unsigned int,unsigned int,unsigned int}]
/home/tony/htpc/Dev/logi/src/db/logi-sqlite.h:182:47:logi::Sqlite3Database::Binder::Binder(logi::Sqlite3Database::Sqlite3StatementBase&,std::tuple&)中必需的[with long unsigned int N=3ul;Args={unsigned int,unsigned int,unsigned int}]
/home/tony/htpc/Dev/logi/src/db/logi-sqlite.h:238:71:void logi::Sqlite3Database::Sqlite3Statement::prepare_row(logi::Sqlite3Database::Sqlite3Statement::Tup&[带参数={unsigned int,unsigned int,unsigned int};logi::Sqlite3Database::Sqlite3Statement::Tup=std::tuple]”
/home/tony/htpc/Dev/logi/src/db/logi-sqlite.h:231:28:void logi::Sqlite3Database::Sqlite3Statement::execute(typename logi::Sqlite3Database::Sqlite3Statement::Parent::ArgsVector&[带Args={unsigned int,unsigned int,unsigned int};typename logi::Sqlite3Database::Sqlite3Statement::Parent::ArgsVector=std::vector]”
/home/tony/htpc/Dev/logi/src/db/logi-sqlite.cpp:354:1:此处需要
/usr/include/c++/6/tuple:1228:12:错误:不完整类型“class std::tuple_element”的使用无效
因此,似乎
std::get
调用正在导致系统库的其他部分(与
std::get
std::tuple
没有直接关系)递归地减少参数。。。这是独立于我对数值模板参数N的递归而发生的。在我的代码中有什么东西我可以在不从根本上改变我的方法的情况下修复吗,或者在元组的模板参数是可变的上下文中不可能使用
std::get

给定C++14
make_index_sequence
函数(及其相关类型),您可以很容易地做您想做的事情:

template<size_t ...indices, typename ...Args>
void binder_helper(Sqlite3StatementBase &s, std::integer_sequence<size_t, indices...>, std::tuple<Args...> &tup)
{
    auto dump = {(s.bind(indices, std::get<indices>(tup)), 0)...};
}

template<typename ...Args>
void binder(Sqlite3StatementBase &s, std::tuple<Args...> &tup)
{
    binder_helper(s, std::make_index_sequence<sizeof...(Args)>(), tup);
}

请注意,在后一种情况下,标准不保证对
s.bind
的调用将按顺序执行。在前一种情况下,因为表达式被包装在一个大括号的init列表中,所以可以保证顺序求值。

您处理问题的方式是错误的。您真正想要的是一个体面的
调用。是的,这是一个C++14工具,但是为C++11找到/编写它的实现并不困难。您在一个包含三个元素的元组上调用
get
,当然这不会编译。这三个元素通过
get
通过
get
检索。你的错误是一个很好的老式错误。我没有一个错误就发现了,谢谢。但我已经将其更改为C++11之前的样式,为等提供了单独的模板。我不认为我需要4个以上的模板,它比变量更简单,最多只需要4个就可以了。@NicolBolas,你的建议很有趣,但我无法计算出
index\u sequence
在不使用包折叠表达式的情况下会有什么帮助;也许这就是你所说的“体面的
调用”的意思?问题是,后者是C++17的一个特性。这对我来说不是问题,但对于那些希望在保守的LTS/stable Linux发行版上构建我的代码的人来说可能是问题。@reah:
不是C++17的功能。这是一个C++11特性。使用
..
for是C++17的一项功能,但是您可以在中使用
..
我知道,C++11/14也支持折叠表达式的基本要素,只要您将它们放在参数列表之类的内容中。这很适合我。@reah:不,那些不是折叠表达式。请阅读我给你的链接。包扩展是C++11的一部分。折叠表达式是包扩展的扩展。我确实读过这些链接,所以请重新阅读我的评论,并理解我所说的“的要点”,我的意思是“功能的基本子集”。@reah:我告诉你这不是折叠表达式!包扩展是折叠表达式的超集,而不是相反。是的,起初我忽略了包扩展和折叠表达式之间的区别,但现在我确实理解了代码中表达的区别,我接受你的答案。我们只是不能在如何用英语表达一些琐碎的语义上达成一致,所以请让我们先别说了。
template<size_t ...indices, typename ...Args>
void binder_helper(Sqlite3StatementBase &s, std::integer_sequence<size_t, indices...>, std::tuple<Args...> &tup)
{
    (s.bind(indices, std::get<indices>(tup)), ...);
}