Get const or non-constant reference type from attribute

I am writing a functor F that takes a function like void (* func) (T) and argument func argument.

template<typename T>
  void F(void (*func)(T), WhatTypeHere? arg)
{
  func(arg);
}

Then the functor F calls func with arg. I would like F not to copy arg, just to pass it as a reference. But then I can’t just write "void F (void (* func) (T), T &)", because T can be a link. Therefore, I am trying to write a trait that allows you to get the correct reference type T:

T -> T&
T& -> T&
const T -> const T&
const T& -> const T&

I come up with something like this:

template<typename T>
 struct type_op
{
 typedef T& valid_ref_type;
};

template<typename T>
 struct type_op<T&>
{
 typedef typename type_op<T>::valid_ref_type valid_ref_type;
};

template<typename T>
 struct type_op<const T>
{
 typedef const T& valid_ref_type;
};

template<typename T>
 struct type_op<const T&>
{
 typedef const T& valid_ref_type;
};


template<typename T>
  void F(void (*func)(T), typename type_op<T>::valid_ref_type arg)
{
  func(arg);
}

What does not work, for example, for

void a(int x) { std::cout << x << std::endl; }
F(&a, 7);

Error on receipt: invalid initialization of a non-constant reference of type 'int & from a temporary type' int in passing argument 2 of 'void F (void (*) (T), typename type_op :: valid_ref_type) [with T = int]

How to make this feature work?

+3
4
template<class T>
struct forwarding { typedef T const& type; };
template<class T>
struct forwarding<T&> { typedef T& type; };

template<typename T>
void F(void (*func)(T), typename forwarding<T>::type arg) {
  func(arg);
}

void a(int x) { std::cout << x << std::endl; }
int main() {
  F(&a, 7);
}

, , T T const & :

T        -> T const&
T&       -> T&
T const& -> T const&

, , T const, T! :

void f(int const);
typedef void F(int); // typedef of function type
F* p = &f; // no error! f signature doesn't include const
+5

, , :

template<typename T> struct remove_reference { typedef T type; };
template<typename T> struct remove_reference<T&> { typedef T type; };

:

remove_reference<T>::type&

​​ :

template<typename T>
void F( void (*func)(T), const typename remove_reference<T>::type& arg )
{
  func(arg);
}
+2

, , boost (, boost:: bind) , const T& ref(x) .

+1
source

You can also use add_referencefrom Boost.TypeTraits to get the required type mapping.

+1
source

Source: https://habr.com/ru/post/1740903/


All Articles