c++ c++11 sfinae typetraits virtual-method

c++ - ¿Cómo detectar si un método es virtual?



c++11 sfinae (2)

Intenté hacer un rasgo para encontrar si un método es virtual : ( https://ideone.com/9pfaCZ )

// Seveval structs which should fail depending if T::f is virtual or not. template <typename T> struct Dvf : T { void f() final; }; template <typename T> struct Dvo : T { void f() override; }; template <typename T> struct Dnv : T { void f() = delete; }; template <typename U> class has_virtual_f { private: template <std::size_t N> struct helper {}; template <typename T> static std::uint8_t check(helper<sizeof(Dvf<T>)>*); template<typename T> static std::uint16_t check(...); public: static constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); };

Casos de prueba:

struct V { virtual void f(); }; struct NV { void f(); }; struct E { }; struct F { virtual void f() final; }; // Bonus (unspecified expected output) static_assert( has_virtual_f< V>::value, ""); static_assert(!has_virtual_f<NV>::value, ""); static_assert(!has_virtual_f< E>::value, "");

Pero obtuve el error: ''void Dvf<T>::f() [with T = NV]'' marked final, but is not virtual .
Si no uso sizeof y directamente Dvf<T>* en check , no tengo error de compilación, pero la check no se descarta para el tipo "incorrecto" en SFINAE :(.

¿Cuál es la forma correcta de detectar si un método es virtual ?


El código no es perfecto pero básicamente pasa las pruebas (al menos en todos los clangs disponibles en wandbox y gcc desde 7.):

#include <type_traits> template <class T> using void_t = void; template <class T, T v1, T v2, class = std::integral_constant<bool, true>> struct can_be_compaired: std::false_type { }; template <class T, T v1, T v2> struct can_be_compaired<T, v1, v2, std::integral_constant<bool, v1 == v2>>: std::true_type { }; template <class T, class = void> struct has_virtual_f: std::false_type { }; template <class T> struct has_virtual_f<T, void_t<decltype(&T::f)>>{ constexpr static auto value = !can_be_compaired<decltype(&T::f), &T::f, &T::f>::value; }; struct V { virtual void f() { } }; struct NV { void f() { } }; struct E { }; struct F { virtual void f() final{ } }; // Bonus (unspecified expected output) int main() { static_assert( has_virtual_f< V>::value, ""); static_assert(!has_virtual_f<NV>::value, ""); static_assert(!has_virtual_f< E>::value, ""); static_assert( has_virtual_f< F>::value, ""); }

[demo en vivo]

Las partes estándar relevantes que teóricamente dejan volar el rasgo: [expr.eq] /4.3 , [expr.const] /2.23


Probablemente no hay manera de determinar si un método específico es virtual . Digo esto porque el proyecto Boost investigó rasgos durante años y nunca produjo tal prueba de rasgos.

Sin embargo, en C ++ 11, o utilizando la biblioteca Boost , puede usar la plantilla is_polymorphic<> para probar un tipo para ver si el tipo tiene funciones virtuales. Consulte std::is_polymorphic<> o boost::is_polymorphic<> para referencia.