Template error: invalid use of incomplete type

1

I found this on the Internet:

#include <utility>
#include <type_traits>

namespace details {

template< typename F, typename Tuple, bool Done, int Total, int... N > struct call_impl {
  static void call( F f, Tuple && t ) {
    call_impl< F, Tuple, Total == 1 + sizeof...( N ), Total, N..., sizeof...( N ) >::call( f, std::forward< Tuple >( t ) );
  }
};

template< typename F, typename Tuple, int Total, int... N > struct call_impl< F, Tuple, true, Total, N... > {
  static void call( F f, Tuple && t ) {
    f( std::get< N >( std::forward< Tuple >( t ) )... );
  }
};

} // namespace details.

template< typename F, typename Tuple > void call( F f, Tuple &&t ) {
  //typedef typename std::decay< Tuple >::type ttype;
  using ttype = typename std::decay< Tuple >::type;

  details::call_impl< F, Tuple, 0 == std::tuple_size< ttype >::value, std::tuple_size< ttype >::value >::call( f, std::forward< Tuple >( t ) );
}

Used to unpack a std::tuple on the arguments of a function call.

The idea is to postpone a function call until necessary, storing the past arguments in a std::tuple and being able to recover them at a later time.

Unfortunately, the template works only with void functions. I'm trying to adapt it to be able to use it in functions with any type of return, but I'm not getting it:

  

error: no matching function for call to 'call (int (&) (int), std :: tuple < int > &)'
  ...
  error: invalid use of incomplete type 'class std :: result_of < int (*) (int) >'

#include <tuple>
#include <functional>
#include <type_traits>

#include <iostream>

namespace details {

template< typename RET, typename F, typename Tuple, bool Done, int Total, int... N > struct call_impl {
  static RET call( F f, Tuple && t ) {
    return call_impl< RET, F, Tuple, Total == 1 + sizeof...( N ), Total, N..., sizeof...( N ) >::call( f, std::forward< Tuple >( t ) );
  }
};

template< typename RET, typename F, typename Tuple, int Total, int... N > struct call_impl< RET, F, Tuple, true, Total, N... > {
  static RET call( F f, Tuple && t ) {
    return f( std::get< N >( std::forward< Tuple >( t ) )... );
  }
};

} // namespace details.

template< typename F, typename Tuple, typename RET = typename std::result_of< F >::type > RET call( F f, Tuple &&t ) {
  //typedef typename std::decay< Tuple >::type ttype;
  using ttype = typename std::decay< Tuple >::type;

  return details::call_impl< RET, F, Tuple, 0 == std::tuple_size< ttype >::value, std::tuple_size< ttype >::value >::call( f, std::forward< Tuple >( t ) );
}

int dummy( int );

int main( ) {
  auto tp = std::make_tuple( 10 );
  auto ret = call( dummy, tp );

  std::cout << "Retorno: " << ret << std::endl;

  return 0;
}

int dummy( int v ) {
  std::cout << "dummy( " << v << " )\n";
  return v + 1;
}

Note: compiled with g++ -Wall -Wextra -std=c++11 -pedantic

    
asked by Trauma 28.02.2018 в 14:56
source

1 answer

2

The problem you have is that F as such does not contain the signature of the function but the type associated with it ... to deduce the return value it is necessary to pass the parameters (think, for example, in the case of overloaded functions).

Peeero clear, you can not pass the parameters because they are contained within the tuple:

template< typename F, typename Tuple, typename RET = typename std::result_of< F >::type > RET call( F f, Tuple &&t ) {
//                             ^^^^^ 

So we need to extract those parameters to be able to deduce the type of return.

Surely it can be more beautiful, but right now I do not have time to clean the code much more.

The code will not compile, as it is stated, with the syntax move , that's why I removed that feature ... but I'm working on it:

template< typename F, typename ... Args, typename ReturnType = typename std::result_of<F&(Args...)>::type>
ReturnType call( F const& f, std::tuple<Args...> t ) {
  using ttype = typename std::decay<std::tuple<Args...>>::type;

  return details::call_impl<ReturnType, F, std::tuple<Args...> , 0 == std::tuple_size< ttype >::value, std::tuple_size< ttype >::value >::call( f, std::forward< std::tuple<Args...> >( t ) );
}
    
answered by 28.02.2018 / 16:02
source