Как определить, является ли метод виртуальным?
Я попытался создать черты, чтобы определить, является ли метод virtual
: (https://ideone.com/9pfaCZ)
// Several 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);
};
Тестовые случаи:
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, "");
Но я получил error: 'void Dvf<T>::f() [with T = NV]' marked final, but is not virtual
.
Если я не использую sizeof
и непосредственно Dvf<T>*
в check
, у меня не возникает ошибка компиляции, но check
не отбрасывается для "плохого" типа в SFINAE :(.
Как правильно определить, является ли метод virtual
?
Ответы
Ответ 1
Код не идеален, но он в основном проходит тесты (по крайней мере, во всех клангах, доступных в wandbox и gcc начиная с 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, "");
}
[живое демо]
Соответствующие стандартные части, которые теоретически позволяют признаку лететь: [expr.eq]/4.3, [expr.const]/2.23
Ответ 2
Вероятно, нет способа определить, является ли конкретный метод virtual
. Я говорю об этом, потому что Boost project изучал черты в течение многих лет и никогда не производил такого теста признаков.
Однако, в С++ 11 или используя Boost library, вы можете использовать шаблон is_polymorphic<>
для проверки типа, чтобы увидеть если тип имеет виртуальные функции. См. std:: is_polymorphic < > или boost:: is_polymorphic < > для справки.