decltype в специализации шаблона класса - PullRequest
3 голосов
/ 21 февраля 2011

Я пытаюсь использовать decltype внутри класса шаблона следующим образом:

#include <functional>
template <typename T>
class A
{
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;

    void f();
};

Это прекрасно работает, но теперь я бы хотел добавить явную специализацию:

template <>
class A<void>
{
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;

    void f();
};

На этот раз g ++ выдает ошибку:

test.cpp:14:33: error: incomplete type 'A<void>' used in nested name specifier

Что я делаю не так? Я использую GCC 4.5.

РЕДАКТИРОВАТЬ: Если я перемещу объявление void f(); выше typedef, как предложено Йоханнесом, я получаю (немного) различные ошибки:

test.cpp:15:62: error: invalid use of incomplete type 'class A<void>'
test.cpp:13:1: error: declaration of 'class A<void>'
test.cpp:15:62: error:   initializing argument 2 of 'std::_Bind<typename std::_Maybe_wrap_member_pointer<_Tp>::type(_ArgTypes ...)> std::bind(_Functor, _ArgTypes ...) [with _Functor = void (A<void>::*)(), _ArgTypes = {A<void>}, typename std::_Maybe_wrap_member_pointer<_Tp>::type = std::_Mem_fn<void (A<void>::*)()>]'
test.cpp:15:62: error: invalid use of incomplete type 'class A<void>'
test.cpp:13:1: error: declaration of 'class A<void>'
test.cpp:15:62: error:   initializing argument 2 of 'std::_Bind<typename std::_Maybe_wrap_member_pointer<_Tp>::type(_ArgTypes ...)> std::bind(_Functor, _ArgTypes ...) [with _Functor = void (A<void>::*)(), _ArgTypes = {A<void>}, typename std::_Maybe_wrap_member_pointer<_Tp>::type = std::_Mem_fn<void (A<void>::*)()>]'

Ответы [ 2 ]

4 голосов
/ 21 февраля 2011

Ваш заказ неверный. Попробуйте обменять его

template <>
class A<void>
{    
    void f();
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;
};

В первичном шаблоне имя A::f было зависимым, и компилятор отложил поиск до точки, где было объявлено f (A::f больше не зависит от C ++ 0x, поскольку A относится к текущая реализация и, следовательно, f члену текущей реализации, но, поскольку в текущей спецификации есть лазейка (это связано с зависимыми базовыми классами), компилятор тем не менее задержал поиск). В явной специализации имя не зависит, и поиск выполняется немедленно, поэтому вам нужно объявить f, прежде чем ссылаться на него.

Редактировать: Вы неправильно используете std::bind. Второй аргумент, который вы даете, имеет тип A<void>, который std::bind будет скопирован / перемещен в созданный объект оболочки вызова. Для этого требуется полный тип A<void>.

Если вы хотите просто передать ссылку на A, для которой вызывается функция-член, вы можете передать declval<A*>(), который механизм std::bind одинаково обнаружит как магический первый аргумент для вызова указателя на член.

Но мне кажется, что вы хотите изучить std::function<>, вместо того, чтобы делать беспорядок std::bind и decltype. В конце концов, у вас есть мощный набор инструментов, но, используя сомнительное выражение decltype, вы отбрасываете всю универсальность, которую дает вам стандартная библиотека, и ограничиваетесь использованием этого единственного выражения std::bind. Это не хорошо.

2 голосов
/ 21 февраля 2011

std :: bind требует A как завершенный тип (см. Ответ Йоханнеса), и поэтому вы не можете использовать его в данный момент.В качестве обходного пути, если вы инкапсулируете some_type, этот скомпилирует :

#include <functional>

template <typename T>
class A
{
  void f();
  struct some_type_helper
  {
    typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;
  };
};

template <>
class A<void>
{
  void f();
  struct some_type_helper;
};

struct A<void>::some_type_helper
{
  typedef decltype(std::bind(&A::f, std::declval<A>())) some_type;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...