получить константный или неконстантный ссылочный тип из черты - PullRequest
3 голосов
/ 13 апреля 2010

Я пишу функтор F, который принимает функцию типа void (* func) (T) и аргумент func arg.

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

Тогда функтор F вызывает func с помощью arg. Я хотел бы, чтобы F не копировал arg, просто чтобы передать его как ссылку. Но тогда я не могу просто написать «void F (void (* func) (T), T &)», потому что T может быть ссылкой. Поэтому я пытаюсь написать характеристику, которая позволяет получить правильный тип ссылки T:

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

Я придумываю что-то вроде этого:

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);
}

Что не работает, например, для

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

Ошибка выдачи: неверная инициализация неконстантной ссылки типа 'int &' из временного типа 'int' при передаче аргумента 2 типа 'void F (void (*) (T), typename type_op :: valid_ref_type) [with T = int]'

Как заставить эту черту работать?

Ответы [ 4 ]

5 голосов
/ 13 апреля 2010
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! Const - это деталь реализации:

void f(int const);
typedef void F(int); // typedef of function type
F* p = &f; // no error! f's signature doesn't include const
2 голосов
/ 13 апреля 2010

Все, что вам нужно, это удалить ссылку:

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);
}
1 голос
/ 13 апреля 2010

Вы также можете использовать add_reference из Boost.TypeTraits для достижения нужного отображения типов.

1 голос
/ 13 апреля 2010

Это немного размыто, но я думаю, что boost (возможно, boost :: bind) решает эту проблему, предоставляя только const T& черты и требуя использования ref(x) для указания неконстантной ссылки.

...