What is a safe way to increment an int in a variadic template expansion?
c++, c++11, variadic-templates
Solution
While mfontanini's solution works and is good because it performs the calculation of the incrementing column index at compile time, I think it's worthwhile pointing out that there is also a direct answer to question of how to increment an int in a variadic pack expansion. (Unfortunately it does not seem to work on GCC due to a bug, see the caveat at the end.)
The answer is based on the fact that while the evaluations of arguments in a function call are unsequenced, the evaluations of arguments in a list initialization are not:
(§8.5.4/4) Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. — end note ]
Therefore, if you transform your function call into something based on a brace-init-list, you'll get the desired effect:
rowCallback(std::tuple<ColumnTypes...> { getColumn<ColumnTypes>(column++)... });
This initializes a `std::tuple` using list-initialization (notice the braces `{ ... }`), hence the `column++` side effect will be performed in left-to-right order.
If written as above, this means you need to change `rowCallback()` to make it accept a `std::tuple` instead of a list of arguments. If you don't like this, you can create a separate template function `call_on_tuple(fun,tup)`, which calls any function `fun` on the arguments that result from expanding tuple `tup`. I once described how to do this here, or if you like, you could use `rlxutil::call_on_tuple` from my GitHub repository.
Your `execute` function then looks like this:
template <typename... ColumnTypes>
void execute(function<void(ColumnTypes...)> rowCallback)
{
using std::tuple;
using rlxutil::call_on_tuple;
int column = 0;
call_on_tuple(rowCallback,
tuple<ColumnTypes...> { getColumn<ColumnTypes>(column++)... });
}
Caveat: This is does not work as expected with GCC. I believe this is because of the bug reported here: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51253.
Problem
I am trying to implement a C++11 wrapper around an SQL library written in C. The C library has separate functions for getting different data types from an SQL statement which require a column index. A simple approach is prototyped below but has a critical flaw: it relies on the order of argument execution, which is not safe (may also have compiler errors, haven't tested it). Question: What is a platform-independent way to safely increment a variable in a variadic template expansion? ``` template< typename... ColumnTypes > void SQLStatement::execute( std::function< void( ColumnTypes... ) > rowCallback ){ while( this->nextRow() ){ int column = 0; rowCallback( this->getColumn< ColumnTypes >( column++ )... ); // unreliable increment ^ } } template< typename T > T SQLStatement::getColumn( const int columnIdx ){} template<> inline int SQLStatement::getColumn< int >( const int columnIdx ){ return sql_library_column_int( this->nativeHandle, columnIdx ); } // Other getColumn specializations here... ```