2017-09-12 6 views
0

J'ai une fonction qui prend un argument appelable basé sur un modèle et lui transmet un index. Dans certaines situations, j'aimerais que cet index soit passé de manière statique (je travaille avec des tuples). Je pensais que cela devrait être possible en passant un objet appelable avec un opérateur d'appel basé sur un modèle et en utilisant SFINAE.Comment envoyer à un opérateur d'appel basé sur un modèle à l'aide de SFINAE

Au début, cela ressemble à quelque chose comme:

struct A { 
    template< size_t I > 
    void operator()(int x) 
    { 
     cout << "A " << x << " " << I << endl; 
    } 
}; 

struct B { 
    void operator()(int x, int i) 
    { 
     cout << "B " << x << " " << i << endl; 
    } 
}; 


template< 
    typename F, 
    size_t I = 0 
> 
inline 
void 
call(int x, F & fn) { 
    fn(x, I); 
} 


int main() 
{ 
    A a;   
    B b; 

    call(2, b); 
    call< B, 3 >(2, b); 

    call(1, a); // no match for call to '(A) (int&, long unsigned int)' 

    return 0; 
} 

J'essaie donc de surcharger la fonction d'appel et choisir le bon appel à l'aide SFINAE:

template< 
    typename F, 
    size_t I = 0 
> 
inline 
typename std::enable_if< /* I've tried all kinds of things here */ >::type 
call(int x, F & fn) { 
    fn<I>(x); 
} 

Mais je ne peux pas comprendre la caractères de type pour détecter si F est appelable avec un paramètre de modèle et un argument int. J'ai référencé this article et this one mais j'ai du mal à les adapter à mon cas d'utilisation. Des idées? Est-il possible sans modifier le site d'appel?

+2

Soyez paresseux et considérez tsking une constante intégrale comme un argument à() au lieu de le prendre comme un argument de type non-type. Template non type arguments passés explicitement ... bien, sucer. – Yakk

+0

semble être une idée intéressante, mais je suis tout à fait clair sur ce que le code est réellement. En fin de compte, tout ce que je fais doit être compatible avec l'appel de 'std :: get', c'est pourquoi je colle avec des arguments non typés de type explicite. – Ian

Répondre

2
struct A { 
    template< std::size_t I > 
    void operator()(int x, std::integral_constant<std::size_t, I> i) { 
    cout << "A " << x << " " << I << endl; 
    } 
}; 

utilisez ceci à la place. Les tests SFINAE standard fonctionnent, pas d'argument de type non-passant.

Dans un compilateur C++ 14, vous pouvez std::get<i>. Dans un compilateur C++ 11, vous pouvez std::get<I> ou std::get<decltype(i)::value>.

Le passage d'arguments de type non-type est nul. Évite-les.

+0

Oui, cela ressemble à une bien meilleure solution, mais je reçois toujours une erreur "aucune correspondance à appeler". 'long unsigned int' ne convertit pas' integral_constant '? http://coliru.stacked-crooked.com/a/e56d8be9bfe754f7 – Ian

+0

@ian passe une constante intégrale et non une valeur. Nommez le type, construisez-le. 'std :: integral_constant {}'. – Yakk

+0

droite, bien sûr: P – Ian