c++ - ambiguous template pattern matching when using variadic template arguments of function overloads -
this should common situation variadic templates example when tree walking children variadic template arguments. find many related questions , answers either different thing or same thing , did not it. problem. have non variadic tuple this
template <class e, class t1, class t2, class t3, etc...> struct x;
and overloading functions have specialized behaviour depending on first element of such tuple being pointer type or vector pointer type. works fine if pack template arguments single variadic template argument, overloads become ambiguous. here error message:
variadic.cpp:42:17: error: ambiguous overload ‘operator<<’ in ‘std::cout << y’ variadic.cpp:42:17: note: candidates are:...
the compiler should prefer x<vector<v*>*,t*...>
on x<h*,t*...>
when tries match vector<double*>*
first element of tuple.
i can disambiguate using enable_if , things work again. understand error , if possible find other means enable_if. here code:
#include <iostream> #include <vector> #include <boost/type_traits/is_fundamental.hpp> #include <boost/utility/enable_if.hpp> using namespace std; template <typename ... t> struct x; template <> struct x <> { }; template <typename h, typename ... t> struct x<h*,t*...> : public x<t*...> { h* value; x(h* value, t*... args) : value(value), x<t*...>(args...) { } }; template <typename h, typename ... t> #ifdef do_not_wanna_see_the_bug typename boost::enable_if<boost::is_fundamental<h>, std::ostream>::type& operator<<(std::ostream& stream, x<h*,t*...> const & x) #else std::ostream& operator<<(std::ostream& stream, x<h*,t*...> const & x) #endif { return stream << "specialized scalar pointer"; } template <typename v, typename ... t> std::ostream& operator<<(std::ostream& stream, x<vector<v*>*,t*...> const & x) { return stream << "specialized vector pointer"; } int main() { double a,b; vector<double *> v; x<double*,double*> x (&a,&b); x<vector<double*>*, double*> y (&v, &b); cout << x << endl; cout << y << endl; // line ambiguous according gcc 4.6 , later }
the essence comment of whozcraig:
when drop t* in both templates program compile (with warnings -wreorder) , give expected output.
operator<<(std::ostream& stream, x<h*,t...> const & x) operator<<(std::ostream& stream, x<vector<v*>*, t...> const & x)
after going through [14] templates without enlightenment, think there compiler bug.
a modified test:
#include <iostream> #include <vector> #include <boost/type_traits/is_fundamental.hpp> #include <boost/utility/enable_if.hpp> using namespace std; #define use_variadic_template 1 #define use_ambiguous 1 template <typename ... t> struct x; template <> struct x <> { }; template <typename h, typename ... t> struct x<h*,t*...> : public x<t*...> { h* value; x(h* value, t*... args) : x<t*...>(args...), value(value) {} }; #if use_variadic_template template <typename h, typename ... t> #if use_ambiguous std::ostream& operator<<(std::ostream& stream, x<h*,t*...> const & x) #else std::ostream& operator<<(std::ostream& stream, x<h*,t...> const & x) #endif #else template <typename h, typename t> std::ostream& operator<<(std::ostream& stream, x<h*, t*> const & x) #endif { return stream << "specialized scalar pointer"; } #if use_variadic_template template <typename v, typename ... t> #if use_ambiguous std::ostream& operator<<(std::ostream& stream, x<vector<v*>*,t*...> const & x) #else std::ostream& operator<<(std::ostream& stream, x<vector<v*>*,t...> const & x) #endif #else template <typename v, typename t> std::ostream& operator<<(std::ostream& stream, x<vector<v*>*, t*> const & x) #endif { return stream << "specialized vector pointer"; } int main() { double a,b; vector<double *> v; x<double*,double*> x (&a,&b); x<vector<double*>*, double*> y (&v, &b); cout << x << endl; cout << y << endl; // line ambiguous according gcc 4.6 , later }
even case:
template <typename h, typename t> std::ostream& operator<<(std::ostream& stream, x<h*, t*> const & x) template <typename v, typename t> std::ostream& operator<<(std::ostream& stream, x<vector<v*>*, t*> const & x)
compiles nicely.
edit: if variadic template hold 1 t passed t* should simple case shown above.
Comments
Post a Comment