【问题标题】:C++ Variadic template - Unable to figure out the compilation errorC++ 可变参数模板 - 无法找出编译错误
【发布时间】:2016-09-30 05:21:22
【问题描述】:

下面是我正在尝试编译的代码(其中的 CPP 部分)

template<typename... T>
void SelectOperation::fetchNextRow(tuple<T...>& row) const
{
    fetchColumn<0, decltype(row), T...>(row, nullptr);
}

template<int index, typename T, typename U>
void SelectOperation::fetchColumn(T& row) const
{
    cout << typeid(row).name();
    std::get<index>(row) = this->get<U>(index + 1);
}

template<int index, typename T, typename U, typename... V>
void SelectOperation::fetchColumn(T& row, void*) const
{
    fetchColumn<index, T, U>(row);
    fetchColumn<index + 1, T, V...>(row, nullptr); //Error at this statement
}

我得到的错误如下:

D:\workspaces\Calzone_Mayank\modules\Figgy\include\common/db/core/SelectOperation.h(149): 
error C2783: 'void figgy::SelectOperation::fetchColumn(T &,void *) const': could not deduce
template argument for 'U'
D:\workspaces\Calzone_Mayank\modules\Figgy\include\common/db/core/SelectOperation.h(58):
note: see declaration of 'figgy::SelectOperation::fetchColumn'
D:\workspaces\Calzone_Mayank\modules\Figgy\include\common/db/core/SelectOperation.h(149):
error C2780: 'void figgy::SelectOperation::fetchColumn(T &) const': expects 1 arguments
- 2 provided

我无法理解为什么无法推断出argument for 'U'。为什么编译器无法确定它应该寻找哪个重载函数?

编辑

fetchNextRow 调用如下所示:

template<typename... T>
void SelectOperation::fetchAllRows(vector<tuple<T...>>& rows) const
{
    while (next())
    {
        tuple<T...> row;
        fetchNextRow<T...>(row);
        rows.push_back(row);
    }
}

vector<tuple<string, string, int>> rows;
SelectOperation o("users", {"name", "employee_id", "age"});
o.fetchAllRows<string, string, int>(rows);

【问题讨论】:

  • 你怎么称呼fetchNextRow

标签: c++ c++11 compiler-errors variadic-templates


【解决方案1】:

考虑一下:

template<int index, typename T, typename U, typename... V>
void SelectOperation::fetchColumn(T& row, void*) const {
    fetchColumn<index, T, U>(row);
    fetchColumn<index + 1, T, V...>(row, nullptr); //Error at this statement
}

V... 为空参数包时,将不起作用。
您使用两个参数(rownullptr)调用了 fetchColumn,因此递归调用了上述函数。
每次使用参数包中的类型时(即U)。
V... 迟早会是一个空参数包,所以你不会有任何U 并且编译器说它既找不到它也无法推断它。

您应该提供两个函数,递归案例和最后一个。
举个例子:

template<int index, typename T, typename U, typename... V>
void SelectOperation::fetchColumn(T& row, void*) const {
    fetchColumn<index, T, U>(row);
    fetchColumn<index + 1, T, V...>(row, nullptr); //Error at this statement
}

template<int index, typename T>
void SelectOperation::fetchColumn(T& row, void*) const {
    // Do whatever you want with your last type...
}

【讨论】:

    【解决方案2】:

    好的,我会试着给你一个方案,你应该如何声明可变参数模板。

    除了转发器的情况,当你可以简单地定义一个可变参数模板版本,它会重定向到另一个可变参数模板函数时,你总是有两个版本,我们称之为关闭打开

    open 版本是带有可变参数模板的版本。这将对下一个参数做一些“延续”。 封闭 版本具有固定数量的参数。最重要的是,编译器可以根据函数重载解析的规则区分这些版本(类似于类模板和部分特化,一旦获得功能方案)。另一件重要的事情当然是开放版本必须包含至少一个固定参数,因为这是将参数包拆分为参数和“其余”的唯一方法。

    一般来说,你有两种可能:

    1. 封闭版使用参数进行操作,开放版进行迭代。例子: template <class T> size_t Size(T arg) { return 1; } template <class T1, class T2, class... Args> size_t Size(T1 t1, T2 t2, Args... args) { return Size(t1) + Size(t2, args...); } 在这种情况下,编译器会区分版本,因为封闭版本使用 一个 参数,而开放版本使用 至少两个 参数。开放版本不能只使用 T1 和 Args,因为这样可以只使用一个参数调用它(Args... 可能是无限数量的参数,包括空列表)。

    2. 封闭版什么都不做(只是终止迭代),开放版完成工作和迭代。例子: size_t Size() { return 0; } template <class T1, class... Args> size_t Size(T1 t1, Args... args) { return 1 + Size(args...); } 在这种情况下,调用:Size(args...) 可能会解析为该函数本身,不同之处在于它将跳过第一个参数,或者如果某个迭代中的args... 列表恰好已经为空,则它会解析为Size()

    我有一种感觉,在您的代码中,您还没有完全决定,您要遵循哪种方案,哪些版本将对数据进行操作,哪些应该继续迭代。您的代码中的确切问题是这个调用:

    fetchColumn<index + 1, T, V...>(row, nullptr);

    有时可能需要解析成这样的声明(因为 V... 解析为空,而模板参数的有效列表是 index+1, T):

    template<int index, typename T> void SelectOperation::fetchColumn(T& row, void*) const

    你还没有声明它。

    【讨论】:

      猜你喜欢
      • 2019-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 2013-12-09
      • 1970-01-01
      • 2011-06-29
      • 1970-01-01
      相关资源
      最近更新 更多