1

Given below is the code(CPP part of it) that I am trying to compile

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 } 

The errors I am getting are as follows:

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 

I am unable to understand why argument for 'U' couldn't be deduced. Why is the compiler unable to determine which overloaded function it should look for?

Edit

The fetchNextRow is called as shown below:

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

AND

vector<tuple<string, string, int>> rows; SelectOperation o("users", {"name", "employee_id", "age"}); o.fetchAllRows<string, string, int>(rows); 
1
  • 1
    How do you call fetchNextRow? Commented Sep 30, 2016 at 5:28

2 Answers 2

2

Consider this:

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 } 

When V... is an empty parameters pack, it won't work.
You invoked fetchColumn with two parameters (row and nullptr), so the mentioned function is called recursively.
Each time you consume a type from your parameters pack (that is U).
Sooner or later, V... will be an empty parameters pack, so you won't have any U and the compiler is saying that it is neither able to find it nor to deduce it.

You should rather provide two functions, the recursive case and the final one.
As an example:

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... } 
Sign up to request clarification or add additional context in comments.

Comments

2

Ok, I'll try to give you a scheme, how you should declare variadic templates.

Except the case of a forwarder, when you can simply define just one variadic-template version, which will redirect to another variadic-template function, you will always have two versions, let's call them closed and open.

The open version is a version with variadic template. This shall do some "continuation" on next arguments. The closed version has a fixed number of arguments. The most important thing is that these versions be distinguishable by the compiler basing on the rules of function overloading resolution (similar it's with the class templates and partial specialization, you'll figure it out easily once you get the scheme for the functions). Another important thing of course is that the open version must contain at least one fixed argument because this is the only way how to split the argument pack into an argument and the "rest".

In general, you have two possibilities:

  1. Closed version operates with argument, Open version does iteration. Example: 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...); } In this case the version are distinguished by the compiler because the closed version uses one argument and the open version uses two at least arguments. The open version cannot use just T1 and Args because this way it could be called with exactly one argument (Args... is potentially unlimited number of arguments including empty list).

  2. Closed version does nothing (just terminates the iteration), Open version does the job and the iteration. Example: size_t Size() { return 0; } template <class T1, class... Args> size_t Size(T1 t1, Args... args) { return 1 + Size(args...); } In this case the call: Size(args...) will potentially resolve into either this function itself, with the difference that it will skip the first argument, or into Size(), if the args... list at some iteration happens to be already empty.

I have a feeling that in your code you haven't exactly decided, which scheme you want to follow, and which of the versions is going to make an operation on the data, and which should continue iteration. The exact problem in your code is that this call:

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

May need to sometimes resolve into such a declaration (because V... resolves to nothing and the effective list of template arguments is index+1, T):

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

and you haven't declared it.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.