C ++ Оператор преобразования для преобразования в указатель на функцию - PullRequest
23 голосов
/ 20 июля 2011

Мне не нравилась идея, которая достаточно проста в моей голове, но я не могу понять, как реализовать в C ++.

Обычно я могу объявить класс с оператором преобразования, как в следующем простом примере:

class Foo
{
private:

    int _i;

public:

    Foo( int i ) : _i(i) { }

    operator int( ) const
    {
        return i;
    }
};

Так что теперь я могу писать такие классные вещи, как

int i = Foo(3);

Но в моем конкретном случае я хотел бы предоставить оператор для преобразования объекта в указатель функции (например, преобразование экземпляра Bar в указатель функции int(*)(int, int)). Вот что я изначально попробовал:

class Bar
{
private:

    int (*_funcPtr)(int, int);

public:

    Bar( int (*funcPtr)(int, int) ) : _funcPtr(funcPtr) { }

    operator int(*)(int, int) ( ) const
    {
        return _funcPtr;
    }

};

Но операторская функция не компилируется, и генерируются следующие ошибки:

expected identifier before '*' token
'<invalid-operator>' declared as a function returning a function

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

Кто-нибудь знает, что такое синтаксис для объявления метода оператора преобразования в указатель на функцию или возможно ли это сделать?

Примечание: я компилирую это с Code :: Blocks, используя GCC 4.5.2. Также приветствуются ответы на некоторые из новых концепций C ++ 0x.

Редактировать

Стремясь упростить пример, я непреднамеренно пропустил одну деталь. Это немного странно, но вместо того, чтобы строго возвращать указатель int(*)(int,int), оператор преобразования предназначен для шаблона:

template<typename ReturnType, typename ArgType1, typename ArgType2>
operator ReturnType(*)(ArgType1, ArgType2) ( ) const
{
    // implementation is unimportant here
}

Насколько я знаю, я больше не могу печатать такой тип. Это явно делает вещи намного более неуклюжими, но я надеюсь, что есть еще способ.

Ответы [ 6 ]

17 голосов
/ 20 июля 2011

Поскольку вы должны знать:

(*operator int() const)(int, int)
{
  return _funcPtr;
}

(Исправлено. Снова.)


Обновление: Мне сообщили Йоханнес Шрауб и ЛюкДантон, этот синтаксис на самом деле недействителен, и вы действительно должны использовать typedef.Поскольку вы говорите, что typedefs не являются опцией, вот вспомогательный класс, который может обернуть ваш typedef:

template<typename R, typename A1, typename A2>
struct MakeFunctionType
{
  typedef R(*type)(A1, A2);
};

template<typename R, typename A1, typename A2>
operator typename MakeFunctionType<R, A1, A2>::type () const
{
    // implementation is unimportant here
}
4 голосов
/ 20 июля 2011

Используйте typedef.В любом случае, его легче читать:

class Bar
{
public:
  typedef int (*fptr_t)(int, int);

  Bar(fptr_t funcPtr) : _funcPtr(funcPtr) { }

  operator fptr_t() const
  {
    return _funcPtr;
  }

private:
  fptr_t _funcPtr;
};

[edit]

Для вашего шаблона я не вижу, как использовать typedef.@Kerrik дает (грязную) версию синтаксиса, которая должна работать.

1 голос
/ 20 июля 2011

Если вы хотите сделать код читабельным, вам нужно , чтобы использовать typedef.Я даже не использую указатели на функции без определения типа, синтаксис слишком ужасный.

Цель:

template<typename ReturnType, typename ArgType1, typename ArgType2>
operator ReturnType(*)(ArgType1, ArgType2) ( ) const
{
   return 0;
}

Путь:

// 1: helper structure
template <typename R, typename A0, typename A1>
struct helper {
  typedef R (*type)(A0,A1);
};

// 2: operator
template <typename R, typename A0, typename A1>
operator typename helper<R, A0, A1>::type() const {
  return 0;
}

Проверить этона ideone !

1 голос
/ 20 июля 2011

EDIT:

Так как ваш класс имеет не шаблонный указатель функции, назначенный при создании:

private:

    int (*_funcPtr)(int, int);

Позднее это вообще невозможно преобразовать в указатель на функцию любого типа.

Поэтому я предполагаю, что вы имели в виду перегрузку оператора члена класса шаблона, а не перегрузку оператора члена шаблона класса.

Версия шаблона:

template<typename ReturnType, typename ArgType1, typename ArgType2>
class Bar {

public:

  typedef ReturnType (*fptr_t)(ArgType1, ArgType2);

  operator fptr_t ( ArgType1 arg1, ArgType2 arg2 ) const
  {
      // implementation is unimportant here
  }

//etc...

};

Затем используется так:

//create functor to some function called myfunc
Bar::fptr_t func_ptr = Bar<int, int, int>(&myfunc); 

//call functor
int i = func_ptr(1,2); 
0 голосов
/ 03 августа 2018

В C ++ 11 можно использовать шаблон псевдонима для преобразования в любую функцию, минуя необходимость в свойстве пользовательского типа struct s.

class Bar
{
    private:


    template<typename ReturnType, typename ArgType1, typename ArgType2>
    using funcptr = ReturnType(*)(ArgType1, ArgType2);

    public:

    template<typename ReturnType, typename ArgType1, typename ArgType2>
    operator funcptr<ReturnType, ArgType1, ArgType2> ( ) const;

};

Чтобы ограничить это значение int(*)(int, int), мы можем использовать SFINAE или static_assert.

0 голосов
/ 03 мая 2017

В GCC работают следующие работы:

template<typename ReturnType, typename ArgType1, typename ArgType2>
operator decltype((ReturnType(*)(ArgType1, ArgType2)) nullptr)() const
{
    // ...
}
...