¿Por qué SFINAE no se aplica a esto?
Pregunta
Estoy escribiendo un código de puntos simple mientras pruebo Visual Studio 10 (Beta 2), y encontré este código donde esperaría que SFINAE se activara, pero parece que no:
template<typename T>
struct point {
T x, y;
point(T x, T y) : x(x), y(y) {}
};
template<typename T, typename U>
struct op_div {
typedef decltype(T() / U()) type;
};
template<typename T, typename U>
point<typename op_div<T, U>::type>
operator/(point<T> const& l, point<U> const& r) {
return point<typename op_div<T, U>::type>(l.x / r.x, l.y / r.y);
}
template<typename T, typename U>
point<typename op_div<T, U>::type>
operator/(point<T> const& l, U const& r) {
return point<typename op_div<T, U>::type>(l.x / r, l.y / r);
}
int main() {
point<int>(0, 1) / point<float>(2, 3);
}
Esto da error C2512: 'point<T>::point' : no appropriate default constructor available
Dado que es una versión beta, hice una verificación rápida de cordura con el compilador comeau en línea y coincide con un error idéntico, por lo que parece que este comportamiento es correcto, pero no veo por qué.
En este caso, algunas soluciones consisten simplemente en alinear el decltype(T() / U())
, para darle a la clase de puntos un constructor predeterminado, o para usar decltype en la expresión de resultado completa, pero recibí este error al intentar simplificar un error que estaba recibiendo con una versión de op_div que no requería un constructor predeterminado*, así que Preferiría mejorar mi comprensión de C++ en lugar de simplemente hacer lo que funciona.
¡Gracias!
*:el original:
template<typename T, typename U>
struct op_div {
static T t(); static U u();
typedef decltype(t() / u()) type;
};
Lo que da error C2784: 'point<op_div<T,U>::type> operator /(const point<T> &,const U &)' : could not deduce template argument for 'const point<T> &' from 'int'
, y también para el point<T> / point<U>
sobrecarga.
Solución
No estoy 100% seguro.Parece que el compilador necesita crear una instancia de ambas sobrecargas para determinar cuál es mejor, pero al intentar crear una instancia del otro op_div con T = int
y U = point<float>
, esto genera un error que no está cubierto por SFINAE (el error no es que op_div no tenga tipo en este caso, pero ese tipo no se puede determinar).
Podría intentar desactivar la segunda sobrecarga si el segundo tipo es un punto (boost::disable_if
).
Además, lo que parece funcionar es la declaración de tipo de retorno pospuesta (eliminando la estructura op_div, pero dependiendo de qué características de C++ 0x son compatibles con su compilador):
template<typename T, typename U>
auto
operator/(point<T> const& l, point<U> const& r) -> point<decltype(l.x / r.x)> {
return {l.x / r.x, l.y / r.y};
}
template<typename T, typename U>
auto
operator/(point<T> const& l, U const& r) -> point<decltype(l.x / r)> {
return {l.x / r, l.y / r};
}
Otros consejos
Diría que su error está aquí:
template<typename T>
struct point {
T x, y;
point(T x, T y) : x(x), y(y) {}
};
Cambie su definición de estructura a esto:
template<typename T>
struct point<T> {
T x, y;
point(T x, T y) : x(x), y(y) {}
};
Si desea utilizar un tipo genérico T, debe especificarlo en la definición.