Re: Variadic function to propagate array indexing doesn't work
correctly
Am 13.04.2012 20:46, schrieb Daryle Walker:
[..]
// Adapted from Dave Abrahams' work on his GitHub account
#define RETURNS(...)
noexcept(noexcept(decltype(__VA_ARGS__)(my_move(__VA_ARGS__)))) \
-> decltype(__VA_ARGS__) { return (__VA_ARGS__); } typedef int \
RETURNS_CAT(RETURNS_, __LINE__)
#define RETURNS_CAT_0(x, y) x ## y
#define RETURNS_CAT(x, y) RETURNS_CAT_0(x,y)
// Test universal multiple-indexing of arrays
// ("Multiply" is the adverb form of "multiple." I think it's pronounced
// differently from the related homograph for doing mulitplication.)
template< typename Array>
inline constexpr
auto index_multiply( Array&&a ) RETURNS( my_forward<Array>(a) );
template< typename Array, typename FirstIndex, typename ...Index>
inline constexpr
auto index_multiply( Array&& a, FirstIndex&& f, Index&& ...i )
RETURNS( index_multiply(my_forward<Array>( a )[ my_forward<FirstIndex>(f) ],
my_forward<Index>( i )...) );
int main()
{
int const table[3][3] = { {2, 3, 5}, {4, 6, 10}, {16, 36, 100} };
assert( index_multiply(table)[1][1] == 6 );
assert( index_multiply(table, 1)[1] == 6 );
//assert( index_multiply(table, 1, 1) == 6 );
return 0;
}
It seems to me that this code (including the currently commented part)
should be well-formed. I can only guess that gcc does not properly find
the same (second) function template at the switch point between
one-element parameter pack expansion and empty parameter pack expansion.
This looks like a compiler defect to me.
I'm using GCC-4.6.3 via MacPorts on a Mac OS X Tiger 10.4.11/PowerPC
32-bit system, if that matters.
I can reproduce the problem with gcc 4.8 snapshot 2012-03-18
Hmm..., looking at this code, I don't know if it's choking on the last
dimension or on anything past the first. (They're the same here since
I have two dimensions total.) Doing:
int const table[3][3][2] = {
{{ 2, 22}, { 3, 33}, { 5, 55}},
{{ 4, 44}, { 6, 66}, { 10, 110}},
{{16, 484}, {36, 4356}, {100, 12100}}
};
assert( index_multiply(table)[1][1][0] == 6 );
assert( index_multiply(table, 1)[1][0] == 6 );
assert( index_multiply(table, 1, 1)[0] == 6 );
assert( index_multiply(table, 1, 1, 0) == 6 );
I get errors on the last two lines ("no matching function for call to
'index_multiply(const int [3][3][2], int, int)'" and "no matching
function for call to 'index_multiply(const int [3][3][2], int, int,
int)'"), so it's any index past the first, all packed into the "...i"
argument. Is the construction of "...i" messed up? Or maybe it's
"a[f]" that's built improperly.
Your second experiment seems to confirm the assumption that there is a
lookup-problem between single and null parameter pack expansion *within*
the declaration of the same function.
For the moment you could use class template specialization instead to
fix the problem. E.g. like so:
template < typename Array, typename ...Index >
struct index_multiply_t;
template < typename Array, typename ...Index >
inline constexpr
auto index_multiply( Array&& a, Index&& ...i )
RETURNS( index_multiply_t<Array, Index...>{}(my_forward<Array>(a),
my_forward<Index>(i)...) )
template < typename Array>
struct index_multiply_t<Array>
{
constexpr auto operator()( Array&& a)
RETURNS( my_forward<Array>(a) )
};
template < typename Array, typename FirstIndex, typename ...Index >
struct index_multiply_t<Array, FirstIndex, Index...>
{
constexpr auto operator()( Array&& a, FirstIndex&& f, Index&& ...i)
RETURNS(
index_multiply(my_forward<Array>(a)[my_forward<FirstIndex>(f)],
my_forward<Index>(i)...) )
};
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]