C ++ - Itère sur une tuple et la résolution de type vs paramètres constants
Question
Je suis en train d'écrire l'opérateur arithmétique surcharge pour tuples. L'opérateur parcourt le tuple pour effectuer l'opération sur chacune de ses éléments individuels. Voici la définition de l'opérateur + =:
template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return lhs;
}
template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
std::get< I >(lhs) += std::get< I >(rhs);
return operator +=< Ts..., I + 1 >(lhs, rhs);
}
Malheureusement, lorsque je tente d'appeler l'opérateur, GCC 4.6 ne peut pas décider de surcharge, il doit utiliser. Par exemple:
std::tuple< int, int, int, int > a = std::make_tuple(1, 2, 3, 4), b = std::make_tuple(5, 6, 7, 8);
a += b;
Rendements l'erreur suivante:
:/Workspace/raster/main.cpp:833:7: instantiated from here
C:/Workspace/raster/main.cpp:809:45: error: no matching function for call to 'operator+=(std::tuple<int, int, int, int>&, const std::tuple<int, int, int, int>&)'
C:/Workspace/raster/main.cpp:809:45: note: candidates are:
C:/Workspace/raster/main.cpp:800:151: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I == sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
C:/Workspace/raster/main.cpp:806:83: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I != sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
Ce qui est étrange puisque la condition de std::enable_if
devrait rejeter l'appel inappropriée. Pour l'instant, je la solution suivante qui était en fait ma mise en œuvre préalable. La version ci-dessus est en fait une tentative de simplification.
template< std::size_t I, typename... Ts >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return lhs;
}
template< std::size_t I, typename... Ts >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple< Ts... >& >::type assignadd_impl(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
std::get< I >(lhs) += std::get< I >(rhs);
return assignadd_impl< I + 1, Ts... >(lhs, rhs);
}
template< typename... Ts >
inline std::tuple< Ts... >& operator +=(std::tuple< Ts... >& lhs, const std::tuple< Ts... >& rhs)
{
return assignadd_impl< 0, Ts... >(lhs, rhs);
}
Cette compile et fonctionne comme prévu. Pourquoi la version simplifiée refuse de dresser des? Merci.
La solution
En utilisant des arguments de modèle explicitement spécifié à un modèle de fonction ou de la classe exige que tous les paquets de paramètres du modèle apparaissent à la fin de la liste globale des paramètres du modèle. Déplacement Ts...
à la fin des listes de paramètres du modèle et la modification des appels fait correctement le travail de code. Section 14.8.2.1 de le courant C ++ 0x projets de états de ce paquets de paramètres qui ne sont pas à la fin de la liste des paramètres du modèle ne peuvent pas être déduites à partir d'un appel de fonction (ce qui rend votre code original échec), mais spécifiant explicitement tous les arguments de modèle à operator+=
dans tous les cas provoque toujours une erreur SFINAE. précédente question a un lien vers le texte exact interdisant ; documentation d'IBM dit qu'il est une erreur aussi bien.