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...
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.
精彩评论