Question

I'm trying to write a generic filtering function that performs linear interpolation at a given sampling coordinate in an multi-dimensional array (arbitrary rank). For this, I need a recursive function template that walks through all dimensions of an array until it hits a value and its associated type. I use boost::enable_if in order to detect when to stop iterating through the dimensions. It works ok until I try to "percolate" the return value/type to the topmost function. For this purpose, I attempted to use C++0x type inference but it doesn't seem to mix well with boost::enable_if.

I isolated the problem down to what follows:

template< typename T, std::size_t I >
auto test(const T &t) -> typename boost::enable_if_c< (I == 0), typename T::value_type >::type
{
    return t[0];
}

template< typename T, std::size_t I >
auto test(const T &t) -> typename boost::enable_if_c< (I > 0), decltype(test< T, I - 1 >(T())) >::type
{
    return test< typename T::value_type, std::size_t(I - 1) >(t[0]);
}

The compiler (GCC 4.6) complains with the following code:

typedef std::array< std::array< float, 1 >, 1 > myarray;
myarray ma;
std::cout << typeid (test< myarray, 1 >(ma)).name() << std::endl;

Error message:

error: conversion from 'boost::enable_if_c<true, float>::type' to non-scalar type 'boost::enable_if_c<true, std::array<float, 1u> >::type' requested

It seems that decltype uses the return value from test< T, I > even though it is instructed to use that of test< T, I - 1 >. Any idea why this behavior occurs? For now, it think I'll just turn the whole thing into a functor...

Was it helpful?

Solution

The issue is that you passed a T() (and T) to decltype. The types aren't folding down. This is clearly revealed if you compare the return expression to what you passed to decltype- they're inconsistent.

template< typename T, std::size_t I >
auto test(const T &t) -> typename boost::enable_if_c< (I > 0), decltype(test< T, I - 1 >(T())) >::type
{
    return test< typename T::value_type, std::size_t(I - 1) >(t[0]);
}

decltype: test<T

return expression: test< typename T::value_type

When defining forward functions like this, the decltype-expression used to define the return type should nearly always be exactly the same as the actual return expression.

Edit: I need to add that you should not pass rvalues when in reality you will pass lvalues, especially to templates, as you may well end up with different results.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top