Opérateur de Conversion C++ pour la conversion en pointeur de fonction

Je me suis écrasé contre une idée assez simple dans ma tête, mais je n'arrive pas à comprendre comment implémenter en C++.

Normalement, je peux déclarer une classe avec un opérateur de conversion, comme dans cet exemple simple:

class Foo
{
private:

    int _i;

public:

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

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

Alors maintenant je peux écrire des trucs géniaux comme

int i = Foo(3);

Mais dans mon cas particulier, je voudrais fournir un opérateur pour convertir un objet en un pointeur de fonction (par exemple, convertir une instance Bar en un pointeur de fonction int(*)(int, int)). Voici ce que j'ai initialement essayé:

class Bar
{
private:

    int (*_funcPtr)(int, int);

public:

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

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

};

Mais la fonction opérateur ne parvient pas à compiler, ces erreurs étant générées:

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

J'ai également essayé des variations simples sur ce qui précède, comme entourer le type de retour entre parenthèses, mais toutes ces idées ont également échoué.

Est-ce que quelqu'un sait quelle est la syntaxe pour déclarer une méthode d'opérateur de conversion en fonction-pointeur, ou s'il est même possible de le faire?

Note: je compile ceci avec Code:: Blocks en utilisant GCC 4.5.2. Les réponses impliquant certains des nouveaux concepts C++0x sont également les bienvenues.

Modifier

Dans mon effort pour simplifier l'exemple, j'ai involontairement laissé de côté un détail. C'est un peu bizarre, mais plutôt que de renvoyer strictement un pointeur int(*)(int,int), l'opérateur de conversion est destiné à être modélisé:

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

Pour autant que je sache, je ne peux plus taper un tel type. Cela rend clairement les choses beaucoup plus maladroites, mais j'espère qu'il y a encore un moyen.

23
demandé sur Ken Wayne VanderLinde 2011-07-20 04:20:57

6 réponses

Puisque vous devez savoir:

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

(fixe. Encore une fois.)


Update: J'ai été informé par Johannes Schraub et Luc Danton que cette syntaxe n'est en fait pas valide, et que vous devez vraiment utiliser un typedef. Puisque vous dites que typedefs ne sont pas une option, voici une classe d'aide qui peut envelopper votre 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
}
17
répondu Kerrek SB 2011-07-22 22:06:51

Utilisez un typedef. C'est plus facile à lire, de toute façon:

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

[Modifier]

Pour votre cas de modèle, je ne vois pas comment utiliser un typedef. @Kerrik donne la version (désordonnée) de la syntaxe qui devrait fonctionner.

4
répondu Nemo 2011-07-20 01:05:22

Modifier:

Puisque votre classe a un pointeur de fonction non template assigné à la construction:

private:

    int (*_funcPtr)(int, int);

Il n'est pas du tout possible de convertir plus tard cela en un pointeur de fonction de n'importe quel type.

Je suppose donc que vous vouliez dire une surcharge d'opérateur de membre de classe de modèle, pas une surcharge d'opérateur de membre de modèle de classe.

Version du modèle:

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...

};

, Puis utilisé comme ceci:

//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); 
1
répondu J T 2011-07-20 00:53:31

Si vous voulez rendre le code lisible, vous besoin d' pour utiliser un typedef. Je n'utilise même pas de pointeurs de fonctions sans les taper, la syntaxe est trop horrible.

Objectif:

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

Chemin:

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

Le Vérifier sur ideone!

1
répondu Matthieu M. 2011-07-20 06:56:29

Ce qui suit fonctionne dans GCC:

template<typename ReturnType, typename ArgType1, typename ArgType2>
operator decltype((ReturnType(*)(ArgType1, ArgType2)) nullptr)() const
{
    // ...
}
0
répondu Vladimir Reshetnikov 2017-05-03 00:48:34

En C++11, Il est possible d'utiliser un modèle d'alias pour convertir n'importe quelle fonction, sans passer par le besoin de caractère de type personnalisé structs.

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;

};

Pour limiter cela à seulement int(*)(int, int), nous pouvons utiliser SFINAE ou static_assert.

0
répondu t.y 2018-08-03 18:49:05