2016-11-18 6 views
4

Есть некоторые различия между clang и gcc. Один из них - это то, как они трактуют указатели на метод. Учитывая следующий код:Объявление указателя на метод с decltype в C++

template <typename T_Class, typename T_Ret, typename ... Args> 
void store_method(T_Class *object, T_Ret (T_Class::*method)(Args ... args)); 

class SomeObjectWithPotentiallyLongName { 
    int commonly_used_method(int var); 
    void register_method() { 
      /* The code below is okay for gcc with -std=gnu++11. But clang 
      * says: 
      * 'reference to non-static member function must be called' */ 
      store_method(this, commonly_used_method); 
      /* To make this fine for clang (and also - gcc), I have to 
      * extend previous line as next */ 
      store_method(this, &SomeObjectWithPotentiallyLongName::commonly_used_method); 
    } 
} 

Код выше показывает необходимость расширения кода во многих местах, чтобы сделать его составитель звоном, в то время как это может быть очень аккуратным и ясно с НКУ.

Самый очевидный способ - написать макрос, который превратил бы и method_name в нечто вроде &TypeOfThis::method_name.

Моя идея состояла в том, чтобы использовать decltype:

#define STORE_METHOD(method) store_method(this, (decltype(*this))::method) 

void SomeObjectWithPotentiallyLongName::register_method() { 
    STORE_METHOD(commonly_used_method); 
} 

Но этот выход кода следующее сообщение об ошибке с clang:

'decltype (* это)' (он же 'SomeObjectWithPotentiallyLongName &') не класс, пространство имен или перечисление

Есть ли способ построить такой макрос? Если нет, есть ли другой способ решить эту проблему?

ответ

3

Well T & не является типом, который можно использовать в этом контексте (как указано в комментариях по-прежнему является типом), это ссылка. Вы можете использовать std::remove_reference<...>::type (documentation), чтобы удалить ссылку и получить T типа вместо:

typedef std::remove_reference<decltype(*this)>::type T; 

И затем использовать:

T::method 
+1

'' Т & является типом. Это может быть не тот тип, который вы хотите, но это тип. –

+0

Да, это работает. Спасибо! – shved

3

Вы пропустили & в макрос. Кроме того decltype может дать квалифицированный ссылочный тип, поэтому следует использовать std::decay для удаления опорных и классификаторов:

#define STORE_METHOD(method)\ 
    store_method(\ 
     this,\ 
     &std::decay<decltype(*this)>::type::method\ 
    ) 

Или std::decay_t в C++ 14:

#define STORE_METHOD(method)\ 
    store_method(\ 
     this,\ 
     &std::decay_t<decltype(*this)>::method\ 
    ) 
+0

Это тоже работает, но Томас был первым. Спасибо. – shved